When porting an open source application or any C (or C++) applications on top of Symbian/S60 using P.I.P.S., the developer will come across situations where C and C++ (and Symbian C++ as well) codes will be used together. The open source community implements a vast number of libraries that export C APIs to the user of such libraries.
While porting such applications, if developers have to intermix C and C++ code, they then have to depend on C++ language features like extern "C" for giving C linkage to some set of APIs. This is required because C and C++ compilers handle function prototype in a different way. C++ compilers use name mangling, (or name decoration) to generate unique names for identifiers in a program. It is because of this technique, in C++, that it is possible to overload any functions (this requires that all the overloaded functions should have a different argument list). The C++ mangled name for any identifier contains all the necessary information that may be needed by the linker, such as linkage type, scope, calling convention, and others.
All identifiers (function names or variable names) declared or defined in C++ source or headers are subject to name mangling. When it comes to C, however, there is nothing called name mangling or overloading. It applies when the developer tries to use C APIs by including corresponding headers. To avoid name mangling, the developer should mention explicitly that those APIs are C APIs, by using the extern "C" keyword.
The syntax of extern "C" is shown below:
extern "C" declaration ;
The declaration (or definition) that immediately follows extern "C" has the C linkage.
extern "C" { declaration ; declaration ; ... }
Everything between the curly braces has C linkage, unless declared otherwise.
While writing header files with C functions which will be included by both C and C++ source files, the user must use extern "C" properly. See the example below:
/*File: GoodCHeader.h */ /* Can be used by C/C++ header and source files directly */ #ifdef __cplusplus extern "C" { #endif /* Write C function declarations here */ void Function1(int, int); char* Function3(char*, int); int Function2(int); #ifdef __cplusplus } /* extern "C" */ #endif
Using ifdef __cplusplus
is required since
C does not support or recognize the extern
keyword. It is
C++ that provides the mechanisms for mixing C and C++ codes in the same program.
To be precise, C++ supports mixing codes that are compiled by C and C++ compatible
compilers in the same program.
If the C header is already defined and it does not have all the APIs defined under extern "C", then while including such a header in C++ source or header files, extern "C" should be used as in the example below:
*File: PureCHeader.h */ /* If C++ header/source files need to include this header, extern "C" should be used*/ /* Define all C APIs here*/ void Function1(int, int); char* Function3(char*, int); int Function2(int); #endif //File: CSource.cpp // C++ source file using PureCHeader.h extern "C" { #include "PureCHeader.h" } void Foo() { // use those C APIs here int ret = Function2(10); }
The developer can use all the features of C++ except templates within C by giving those functions extern "C" linkage. See the example below:
#include <iostream> using namespace std; extern "C" { //Can give C linkage to this class!! class Sample{ public: Sample(int a = 10) : iMem(a) { } void Display() { cout<<"iMem is : "<<iMemend1; } private: int iMem; }; /* //Can not give C linkage to template!! //If we uncomment this code, then it will give a compilation error. template<class DataType> void Foo(DataType data) { }*/ }
Using C linkage, C codes like structures and functions that manipulate those structures can be extended efficiently in a C++ source file as in the example below:
/* File: CHeader.h */ typedef struct{ char* name; int id; float price; } Item; int Push(Item* item); int Pop(Item* item); /* File: CppHeader.h */ //Give external linkage to C structure extern "C" { # include "CHeader.h" } class MyStack : public Item { public: MyStack(char* aName, int aId, float aPrice) : name(aName), id(aId), price(aPrice) { } int PushOnToStack() { return Push(this);} int PopFromStack() { return Pop(this); } };