Tutorial 05: Mixing C and C++ Code: Part 1: Issues and Resolutions
Tutorial 05: Mixing C and C++ Code: Part 1: Issues and Resolutions
Partha Pratim
Das
Objectives &
Programming in Modern C++
Outline
Tutorial T05: Mixing C and C++ Code: Part 1: Issues and Resolutions
Mixing C & C++
Why Mix C/C++?
Build all in C++
Mix C & C++
Static Initialization
Compiler
Partha Pratim Das
Compatibility
Linkage Issues
Exception Issues Department of Computer Science and Engineering
Common Mix
Indian Institute of Technology, Kharagpur
C from C++
C++ from C [email protected]
Pointers to Functions
C Header File
System All url’s in this module have been accessed in September, 2021 and found to be functional
Non-System
Tutorial Summary
Tutorial T05
Partha Pratim • Due to legacy, reuse and several business compulsions, we often need to mix C and
Das
C++ codes in the same project
Objectives &
Outline • So we need to learn how to write programs mixing C and C++?
Mixing C & C++
Why Mix C/C++?
Build all in C++
Mix C & C++
Static Initialization
Compiler
Compatibility
Linkage Issues
Exception Issues
Common Mix
C from C++
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary
Tutorial T05
1 Mixing C and C++ Codes
Partha Pratim
Das Why Mix C/C++?
Objectives &
Build all in C++
Outline Mix C and C++
Mixing C & C++ Static Initialization
Why Mix C/C++?
Compiler Compatibility
Build all in C++
Mix C & C++
Linkage Issues
Static Initialization Exception Issues
Compiler
Compatibility
Linkage Issues
2 Common Code Mix Scenarios
Exception Issues How do I call a C function from C++?
Common Mix
C from C++
How do I call a C++ function from C?
C++ from C How do I use Pointers to C / C++ Functions?
Pointers to Functions
C Header File
How do I include a C Header File?
System System Header File
Non-System Non-System Header File
Tutorial Summary
3 Tutorial Summary
Programming in Modern C++ Partha Pratim Das T05.3
Mixing C and C++ Codes
Tutorial T05
Partha Pratim
Das
Objectives &
Outline
Common Mix
C from C++
C++ from C
Pointers to Functions
Mixing C and C++ Codes
C Header File
System
Non-System Source:Accessed 16-Sep-21
How to mix C and C++, ISO CPP
Tutorial Summary Mixing C and C++ Code in the Same Program, Oracle
C++ Core Guidelines: Mixing C with C++
Mixing Code in C, C++, and FORTRAN on Unix
Programming in Modern C++ Partha Pratim Das T05.4
Why do we need to mix C and C++ Codes?
Tutorial T05 • Primary reason is legacy and reuse. There are possibly trillion lines of well-tested C
Partha Pratim
Das
code available. So reusing them in and / or with C++ needs mixing of codes
• Mixing of codes is actually often needed not only across C and C++, it may be used
Objectives &
Outline across C and Python, C# and Python, C++ and Java, and so on to get the best of
Mixing C & C++ both languages (C/C++ is efficient, C if lightweight for embedded programming,
Why Mix C/C++?
Build all in C++
Python has rich libraries and good for web, Java is good for applications with GUI etc.)
Mix C & C++ and be able to use the available proven libraries. Actually, we may mix more than
Static Initialization
Compiler two languages
Compatibility
Linkage Issues • Here are some informative articles on projects using multiple languages:
Exception Issues
◦ Polyglot programming – development in multiple languages, Computer World, 2009
Common Mix
C from C++
◦ How do you use different coding languages in one program?, Quora, 2015 and several
C++ from C other in Ouora
Pointers to Functions
C Header File
◦ A Large Scale Study of Multiple Programming Languages and Code Quality, IEEE, 2016
System ◦ On multi-language software development, cross-language links and accompanying tools: a
Non-System
survey of professional software developers, Springer, 2017
Tutorial Summary
• We restrict the discussions here on mixing C and C++ only
All links Accessed on 21-Sep-21
Programming in Modern C++ Partha Pratim Das T05.5
Why do we need to mix C and C++ Codes?
Tutorial T05
• Build as C++: In a mixed code projct where all header and source files are available and
Partha Pratim
Das
editable, we can compile all the code (even the C-style code) using a C++ compiler. For
example, using g++ for both .c and .cpp files. That eliminates the need to mix C and C++
Objectives &
Outline • However, it is not easy to build the C code by C++ compiler unless the C code strictly uses
Mixing C & C++ the common subset of C and C++ (Check the Tutorial on Compatibility of C and C++ for
Why Mix C/C++?
Build all in C++
details). For example, consider the simple C program below where difference of behavior in C
Mix C & C++ and C++ compilers are marked in different colors:
Static Initialization
Compiler
/* cStyle.c */
Compatibility #include <stdio.h>
Linkage Issues int main() {
Exception Issues
double sq2=sqrt(2); // (1): math.h missing. Warning in C89. Error in C++98
Common Mix printf("sizeof(’a’): %d",
C from C++ sizeof(’a’)); // (2): ’a’ is int in C, char in C++. Outputs 4 in C89. Outputs 1 in C++98
C++ from C char c;
Pointers to Functions void* pv = &c;
C Header File int* pi = pv; // (3): Implicit conversion from void* to int*. Okay in C89. Error in C++98
System
int class = 5; // (4): class is a reserved word in C++. Okay in C89. Error in C++98
Non-System
}
Tutorial Summary
• So the C code needs to be ported for C++
Programming in Modern C++ Partha Pratim Das T05.7
Build C and C++ Codes as C++
Tutorial T05
• Build as C++: While building a C/C++ project (both C and C++ codes) with C++
Partha Pratim
Das is preferable from language perspective it has a number of shortcomings from
Objectives &
engineering viewpoint
Outline
◦ The C-style code may need porting as the C++ compiler is more strict - as we have
Mixing C & C++
Why Mix C/C++? seen in the example
Build all in C++
Mix C & C++
◦ Porting may involve substantial cost in terms of developer effort as well as project
Static Initialization time. This may not be affordable from the business perspectives
Compiler
Compatibility ◦ With porting we also need to create new testplan for C++, perform extensive
Linkage Issues
Exception Issues
testing to match the regression. This involves further cost in terms of tester effort
Common Mix as well as project time. This may not be affordable from the business perspectives
C from C++
C++ from C
◦ If we are porting a stable C code, even after regression clean and testing, it is likely
Pointers to Functions to break some of the existing functionality in the software or even in customer’s
C Header File
System
code if the C code is part of a library provided to the customer. This too may not
Non-System
be affordable from the business perspectives
Tutorial Summary
◦ So building as C++ is feasible only in some select situations though it is preferred
Programming in Modern C++ Partha Pratim Das T05.8
Mixing C and C++ Codes: Issues and Remedies
Tutorial T05
• When we mix codes, that is, compile C code by C Compiler and C++ code by C++
Partha Pratim
Das
Compiler - all into .o files - we expect to be free from language-specific issues in
individual translation units
Objectives &
Outline
• However, issues arise as we work with different versions of compilers, link the .o files of
Mixing C & C++
Why Mix C/C++?
translation units, and as control flows across units during execution, and so on:
Build all in C++
Mix C & C++
◦ Static Initialization Issues: While compiling main(), static initialization is handled
Static Initialization differently in C and C++
Compiler
Compatibility ◦ Compiler Incompatibility Issues: The compilers may have incompatibility in calling
Linkage Issues
Exception Issues
conventions, definitions of basic types (like int, pointer), runtime library, etc.
Common Mix ◦ C Library Incompatibility Issues: If the C++ compiler provides its own versions of
C from C++
C++ from C
the C headers, the headers used by the C compiler must be compatible
Pointers to Functions ◦ Linkage Issues: C and C++ linkage conventions differ
C Header File
System
◦ Exception Issues: C and C++ use drastically different exception models
Non-System
◦ Scope of struct Issue: Scoping of nested struct differ between C and C++.
Tutorial Summary
Check the Tutorial on Compatibility of C and C++ for details
Programming in Modern C++ Partha Pratim Das T05.9
Mixing C and C++ Codes: Issues and Remedies
Tutorial T05 • Static Initialization Issues: In C and C++ both the static variables are constructed and
Partha Pratim initialized before main(). But they have different semantics and handling for static
Das
◦ In C, a static initializer must be a constant
Objectives &
Outline ◦ In C++, a static variable must be constructed – its constructor must get called
Mixing C & C++ So the following code compiles in C++, but fails in C
Why Mix C/C++?
Build all in C++ #include <stdio.h>
Mix C & C++ int init(void) { return 10; }
Static Initialization
Compiler static int i = init(); /* Error in C: initializer element is not constant. Okay in C++ */
Compatibility
Linkage Issues
Exception Issues
int main() { printf("i = %d", i); }
Common Mix Hence,
C from C++
C++ from C ◦ C++ compiler generates an additional Start function, where all global function calls
Pointers to Functions
C Header File (including constructors) are executed before main starts
System ◦ C compiler does not generate such Start function, main starts as soon as it is loaded
Non-System
Tutorial T05
Partha Pratim • Compiler and C Library Incompatibility Issues: To allevite the problems outlined,
Das
we should
Objectives &
Outline ◦ Use compilers (preferably) from the same vendor (say, gcc)
Mixing C & C++ ◦ Have same / compatible versions (for example, use the same calling conventions,
Why Mix C/C++?
Build all in C++
define basic types such as int, float or pointer in the same way)
Mix C & C++ ◦ C runtime library must also be compatible with the C++ compiler
Static Initialization
Compiler ◦ If the C++ compiler provides its own versions of the C headers, the versions of
Compatibility
Linkage Issues those headers used by the C compiler must be compatible
Exception Issues
So,
Common Mix
C from C++ ◦ RULE 2: C and C++ compilers must be compatible
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary
Tutorial T05 • Linkage Issues: Consider C++ code with 2 overloads of print() in multiple scopes
Partha Pratim
#include <iostream>
Das using namespace std;
void print(int) { cout << "int" << endl; } // Global
Objectives & void print(double) { cout << "double" << endl; }
Outline class MyClass { int i; double d; const char *pc; public:
Mixing C & C++ MyClass(int _i = 1, double _d = 1.1, const char *_pc = "Hello") : i(_i), d(_d), pc(_pc) { }
Why Mix C/C++? void print(int) { cout << "MyClass int " << i << endl; } // Class member
Build all in C++ void print(double) { cout << "MyClass double " << d << endl; }
Mix C & C++ };
Static Initialization class MyOtherClass { public:
Compiler
Compatibility
static void print(int) { cout << "MyOtherClass int " << endl; } // Class static member
Linkage Issues
static void print(double) { cout << "MyOtherClass double " << endl; }
Exception Issues };
namespace MySpace {
Common Mix
void print(int) { cout << "MySpace int" << endl; } // namespace member
C from C++
C++ from C
void print(double) { cout << "MySpace double" << endl; }
Pointers to Functions
}
C Header File
int main() { MyClass a;
System print(10); print(10.10);
Non-System a.print(10); a.print(10.10);
Tutorial Summary
MyOtherClass::print(10); MyOtherClass::print(10.10);
MySpace::print(10); MySpace::print(10.10);
}
Programming in Modern C++ Partha Pratim Das T05.13
Mixing C and C++ Codes: Issues and Remedies
Tutorial T05 • Linkage Issues: The mangled and un-mangled names of functions are:
Partha Pratim
Das Function gcc 6.3.0 msvc 18.00 Mangled?
Objectives & // Global: Overloaded
Outline print(int) Z5printi ?print@@YAXH@Z Yes
Mixing C & C++ print(double) Z5printd ?print@@YAXN@Z Yes
Why Mix C/C++? // Class member: Overloaded
Build all in C++ MyClass::print(int) ZN7MyClass5printEi ?print@MyClass@@QAEXH@Z Yes
Mix C & C++ MyClass::print(double) ZN7MyClass5printEd ?print@MyClass@@QAEXN@Z Yes
Static Initialization // Class static member: Overloaded
Compiler
Compatibility
MyOtherClass::print(int) ZN12MyOtherClass5printEi ?print@MyOtherClass@@SAXH@Z Yes
Linkage Issues MyOtherClass::print(double) ZN12MyOtherClass5printEd ?print@MyOtherClass@@SAXN@Z Yes
Exception Issues // namespace member: Overloaded
Common Mix
MySpace::print(int) ZN7MySpace5printEi ?print@MySpace@@YAXH@Z Yes
C from C++ MySpace::print(double) ZN7MySpace5printEd ?print@MySpace@@YAXN@Z Yes
C++ from C // Global: Not Overloaded
Pointers to Functions main() main main No
C Header File
System
Non-System Therefore C and C++ compilers need to handle the names differently. As C compiler
Tutorial Summary does not know about mangling, we need to tell the C++ compiler not to mangle the
names in the C context
Programming in Modern C++ Partha Pratim Das T05.14
Mixing C and C++ Codes: Issues and Remedies
Tutorial T05 • Linkage Issues: The extern "C" linkage specifier can prevent the C++ compiler from
Partha Pratim mangling the names. Declaring a function within extern "C" in the code, we can call a C
Das
function from C++, or a C++ function from C. We may use extern "C"
Objectives &
Outline
◦ for each function
extern "C" void foo(int);
Mixing C & C++
Why Mix C/C++?
◦ for each function in a scope
Build all in C++ extern "C" {
Mix C & C++ void foo(int);
Static Initialization double bar(double);
Compiler };
Compatibility
Linkage Issues
◦ or for the entire header file by using include guards
Exception Issues #ifdef __cplusplus
extern "C" {
Common Mix
#endif
C from C++
C++ from C
void foo(int);
Pointers to Functions
double bar(double);
C Header File ...
System #ifdef __cplusplus
Non-System }
Tutorial Summary
#endif
Note that the macro cplusplus is defined when the C++ compiler is used. Hence, extern
"C" is not exposed to C compiler (it does not recognize it)
Programming in Modern C++ Partha Pratim Das T05.15
Mixing C and C++ Codes: Issues and Remedies
Tutorial T05
Partha Pratim • Linkage Issues: As we have seen, using extern ”C” within cplusplus guard, we can
Das
make a header that works appropriately for C and C++ both. For an illustrative
Objectives &
Outline
example, you may refer to the video: C Programming — Advance Topic And Mixing C
Mixing C & C++
with C++ Code, YouTube (Accessed 19-Sep-21)
Why Mix C/C++?
Build all in C++
We now have the next rule:
Mix C & C++
Static Initialization
◦ RULE 3: C++ compiler should direct the linking process (so it can get its
Compiler
Compatibility
special libraries)
Linkage Issues
Exception Issues
Common Mix
C from C++
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary
Tutorial T05 • Exception Issues: C and C++ use different exception models
Partha Pratim
Das
◦ Propagating Exceptions
. What happens if a C++ function is called from a C function, and the C++
Objectives &
Outline function throws an exception? The C++ standard is somewhat vague this
Mixing C & C++ . In some systems like Oracle Developer Studio C++ this will work properly. In it
Why Mix C/C++?
Build all in C++ if a C function is active when a C++ exception is thrown, the C function is
Mix C & C++
Static Initialization
passed over in the process of handling the exception
Compiler
Compatibility
◦ Mixing Exceptions with set jmp and long jmp
Linkage Issues
Exception Issues
. The C++ exception mechanism and C++ rules about destroying objects that go
Common Mix out of scope are likely to be violated by a long jmp, with unpredictable results
C from C++
C++ from C
. Some C++ experts believe that long jmp should not be integrated with
Pointers to Functions exceptions, due to the difficulty of specifying exactly how it should behave.
C Header File
System
. If we must use long jmp in C code that we are mixing with C++, we need to
Non-System
ensure that a long jmp does not cross over an active C++ function
Tutorial Summary
Tutorial T05
Partha Pratim
Das
Objectives &
Outline
Common Mix
C from C++
C++ from C
Pointers to Functions
Common Code Mix Scenarios
C Header File
System
Non-System
Tutorial Summary
Tutorial T05
• How do I call a C function from C++? • How do I include a C Header File?
Partha Pratim
Das • How do I call a C++ function from C? ◦ System / Standard Library Headers
Objectives & ◦ Non-Member ◦ Non-System / User-defined Headers
Outline
. Global / namespace . Editable Headers
Mixing C & C++
. static . Non-Editable Headers
Why Mix C/C++?
Build all in C++ ◦ Member • How do I use Pointers to C / C++
Mix C & C++
Static Initialization . Non-static Functions?
Compiler − Non-virtual • How do I manipulate with objects in a
Compatibility
Linkage Issues
− virtual
Exception Issues . static C / C++ mix project?
Common Mix
C from C++
◦ Overloaded
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary
Tutorial T05 • Declare the C function extern "C" (in the C++ code) and call it (from the C or C++ code):
Partha Pratim
Das // C++ code /* C code: */
extern "C" void f(int); // one way void f(int i) {
Objectives & extern "C" { // another way /* ... */
Outline
int g(double); }
Mixing C & C++ double h(); int g(double d) {
Why Mix C/C++? }; /* ... */
Build all in C++
void code(int i, double d) { }
Mix C & C++
f(i); double h() {
Static Initialization
int ii = g(d); /* ... */
Compiler
Compatibility double dd = h(); }
Linkage Issues // ...
Exception Issues } Note that C code does not need to be edited
Common Mix
So pre-compiled .o file may also be used
C from C++
C++ from C • Note that C++ type rules, not C rules, are used. So a function declared extern "C" cannot
Pointers to Functions
C Header File
be called with the wrong number of arguments. For example:
System // C++ code
Non-System void more_code(int i, double d) {
Tutorial Summary double dd = h(i,d); // error: unexpected arguments
// ...
}
Programming in Modern C++ Partha Pratim Das T05.20
How do I call a C++ function from C?:
Non-Member and Member Functions
Tutorial T05 • Declare the C+ extern "C" (in the C++ code) and call it (from the C or C++ code):
Partha Pratim
Das // C++ code /* C code: */
extern "C" void f(int); void f(int);
Objectives & void f(int i) { void cc(int i) {
Outline
// ... f(i);
Mixing C & C++ } /* ... */
Why Mix C/C++? // This works only for non-member functions }
Build all in C++
Mix C & C++
Static Initialization
• To call member functions (including virtual functions) from C, a simple wrapper needs to be
Compiler provided. For example:
Compatibility
Linkage Issues
Exception Issues // C++ code /* C code: */
class C { double call_C_f(struct C* p, int i);
Common Mix
C from C++
// ... void ccc(struct C* p, int i) {
C++ from C
virtual double f(int); double d = call_C_f(p,i);
Pointers to Functions
}; /* ... */
C Header File // wrapper function }
System extern "C"
Non-System double call_C_f(C* p, int i) {
Tutorial Summary
return p->f(i);
}
Partha Pratim • To call overloaded functions from C, wrappers, with distinct names for the C code to use, must
Das
be provided. For example:
Objectives &
Outline // C++ code /* C code: */
Mixing C & C++ void f(int); void f_i(int);
Why Mix C/C++? void f(double); void f_d(double);
Build all in C++ extern "C" void f_i(int i) { f(i); } void cccc(int i,double d) {
Mix C & C++ extern "C" void f_d(double d) { f(d); } f_i(i);
Static Initialization f_d(d);
Compiler /* ... */
Compatibility
Linkage Issues
}
Exception Issues
Note that these techniques can be used to call a C++ library from C code even if it is
Common Mix
C from C++ not desirable or possible to modify the C++ headers
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary
Tutorial T05 • A pointer to a function must specify whether it points to a C function or to a C++
Partha Pratim
Das
function:
typedef int (*pfun)(int); // pfun points to a C++ function
Objectives & extern "C" void foo(pfun); // foo is a C function taking a pointer to a C++ function
Outline
extern "C" int g(int) // g is a C function
Mixing C & C++
...
Why Mix C/C++?
Build all in C++
// Type Mismatch Error!
Mix C & C++ foo(g); // foo called with a pointer to g, a C function
Static Initialization
Compiler
Compatibility
• To match the linkage of a pointer-to-function with the functions to which it will point,
Linkage Issues all declarations in this example needs to be inside extern "C" brackets, ensuring that
Exception Issues
the types match
Common Mix
C from C++ extern "C" {
C++ from C typedef int (*pfun)(int);
Pointers to Functions
void foo(pfun);
C Header File
System
int g(int);
Non-System }
Tutorial Summary ...
foo(g); // Types Match. Now OK
Programming in Modern C++ Partha Pratim Das T05.23
How can I include a standard C header file in my C++ code?
Tutorial T05
Partha Pratim • #includeing a standard header file such as <cstdio>, is nothing unusual. For example:
Das
Common Mix
It is possible that a C++ program include a C header as in C. Like:
C from C++
C++ from C
#include <math.h> // Not in std namespace
Pointers to Functions ...
C Header File sqrt(5.0); // Use without std::
System
Non-System This, however, is not preferred
Tutorial Summary
• Using .h with C++ header files, like iostream.h, is disastrous. These are deprecated. It is
dangerous, yet true, that some compilers do not error out on such use. Exercise caution.
Programming in Modern C++ Partha Pratim Das T05.25
How can I include a non-system C header file in my C++ code?:
Editable Case
Tutorial T05
Partha Pratim • If the C header is editable, add the extern "C" {...} logic inside the header and
Das
guard it by cplusplus to let C compiler to ignore it
Objectives &
Outline #ifdef __cplusplus /* C++ compiler notes, C compiler ignores */
Mixing C & C++ extern "C" {
Why Mix C/C++? #endif
Build all in C++
Mix C & C++ void f(int i, char c, float x) /* Original Code of the Header */
Static Initialization
Compiler
Compatibility
#ifdef __cplusplus
Linkage Issues }
Exception Issues #endif
Common Mix Now the C header may be #included without extern "C" in the C++ code:
C from C++
C++ from C
Pointers to Functions
// C++ code
C Header File // Get declaration for f(int i, char c, float x)
System #include "my-C-code.h" // Note: nothing unusual in #include line
Non-System int main() {
Tutorial Summary
f(7, ’x’, 3.14); // Note: nothing unusual in the call
// ...
}
Programming in Modern C++ Partha Pratim Das T05.26
How can I include a non-system C header file in my C++ code?:
Non-Editable Case
Tutorial T05
Partha Pratim • If the C header is not editable, the #include line must be wrapped in an extern ”C” {
Das
/*...*/ } construct. This tells the C++ compiler that the functions declared in the
Objectives &
Outline
header file are C functions
Mixing C & C++
// C++ code
Why Mix C/C++?
extern "C" {
Build all in C++
Mix C & C++
// Get declaration for f(int i, char c, float x)
Static Initialization
#include "my-C-code.h"
Compiler }
Compatibility
Linkage Issues
int main() {
Exception Issues
f(7, ’x’, 3.14); // Note: nothing unusual in the call
Common Mix // ...
C from C++ }
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary
Tutorial T05
Partha Pratim • We have learnt why is it often necessary to mix C and C++ codes in the same project
Das
• We have explored the basic issues of mixing and learnt the ground rules
Objectives &
Outline • In addition to the rules, we have three mechanisms to ease code mixing
Mixing C & C++
Why Mix C/C++?
◦ Use extern "C" in C++ for all functions to be called from both C and C++
Build all in C++
Mix C & C++
◦ Guard extern "C" with cplusplus guard for use with C
Static Initialization ◦ Provide wrappers for C++ data members, member functions, and overloaded
Compiler
Compatibility functions for use with C
Linkage Issues
Exception Issues
Common Mix
C from C++
C++ from C
Pointers to Functions
C Header File
System
Non-System
Tutorial Summary