C Language Preprocessor and Macros __cplusplus for using C externals in C++ code compiled with C++ - name mangling


Example

There are times when an include file has to generate different output from the preprocessor depending on whether the compiler is a C compiler or a C++ compiler due to language differences.

For example a function or other external is defined in a C source file but is used in a C++ source file. Since C++ uses name mangling (or name decoration) in order to generate unique function names based on function argument types, a C function declaration used in a C++ source file will cause link errors. The C++ compiler will modify the specified external name for the compiler output using the name mangling rules for C++. The result is link errors due to externals not found when the C++ compiler output is linked with the C compiler output.

Since C compilers do not do name mangling but C++ compilers do for all external labels (function names or variable names) generated by the C++ compiler, a predefined preprocessor macro, __cplusplus, was introduced to allow for compiler detection.

In order to work around this problem of incompatible compiler output for external names between C and C++, the macro __cplusplus is defined in the C++ Preprocessor and is not defined in the C Preprocessor. This macro name can be used with the conditional preprocessor #ifdef directive or #if with the defined() operator to tell whether a source code or include file is being compiled as C++ or C.

#ifdef __cplusplus
printf("C++\n");
#else
printf("C\n");
#endif

Or you could use

#if defined(__cplusplus)
printf("C++\n");
#else
printf("C\n");
#endif

In order to specify the correct function name of a function from a C source file compiled with the C compiler that is being used in a C++ source file you could check for the __cplusplus defined constant in order to cause the extern "C" { /* ... */ }; to be used to declare C externals when the header file is included in a C++ source file. However when compiled with a C compiler, the extern "C" { */ ... */ }; is not used. This conditional compilation is needed because extern "C" { /* ... */ }; is valid in C++ but not in C.

#ifdef __cplusplus
// if we are being compiled with a C++ compiler then declare the
// following functions as C functions to prevent name mangling.
extern "C" {
#endif

// exported C function list.
int foo (void);

#ifdef __cplusplus
// if this is a C++ compiler, we need to close off the extern declaration.
};
#endif