Why You Shouldn’t Put #include Inside extern "C" and How to Use It Correctly
This article explains the low‑level mechanics of extern "C", why placing #include directives inside an extern "C" block can cause name‑mangling and linkage errors, and provides practical guidelines and code examples for safely mixing C and C++ headers.
Background: name mangling and linkage
C++ compilers apply name mangling to every externally visible identifier, encoding type information so that functions can be overloaded and namespaces can coexist. The resulting symbol names are unique but differ from the original source names. In contrast, C uses a flat namespace with no mangling; symbols appear exactly as written (often with a simple leading underscore).
When linking C++ object files with C object files, the mismatched symbol names cause undefined‑symbol errors unless the C symbols are exposed with C linkage.
Purpose of extern "C"
extern "C"is a linkage specification that tells the C++ compiler to treat the declared functions or variables as if they were compiled by a C compiler: no name mangling, C calling convention, and C‑compatible symbol names.
Typical usage
extern "C" {
void foo();
int bar();
}For a single declaration you can write extern "C" void foo();.
Conditional application for mixed C/C++ headers
Because a pure C compiler does not understand extern "C", the usual pattern is to guard the specification with the predefined macro __cplusplus:
#ifdef __cplusplus
extern "C" {
#endif
void foo();
int bar();
#ifdef __cplusplus
}
#endifThis makes the header usable by both C and C++ source files.
Illustrative example
Assume a C header my_handle.h declares three functions. Compiling it with a C compiler produces an object file my_handle.o whose symbol table contains the unmangled names. A C++ source file that includes the same header without the conditional extern "C" will mangle the names, leading to linker errors.
Applying the conditional block above restores compatibility; after recompiling the C++ file, the symbol table matches that of my_handle.o and linking succeeds.
Why not place #include directives inside extern "C" ?
Nesting a linkage specification is allowed, but the innermost specification wins. If a header included inside an extern "C" block contains C++‑only declarations, those declarations will unintentionally be given C linkage, breaking overloads or namespace semantics. Some compilers (e.g., older MSVC versions) even reject deep nesting.
Therefore, keep all #include statements outside the extern "C" block and wrap only the declarations that truly need C linkage.
Best practices
Wrap only function and variable declarations (or definitions) that must be callable from C in extern "C".
Leave structs, enums, macros, and other non‑function entities outside; they are unaffected by linkage.
Use the __cplusplus macro to conditionally apply the specification, preserving pure‑C compatibility.
Define a small helper macro (e.g., C_LINKAGE_BEGIN / C_LINKAGE_END) in a dedicated header to avoid repetitive boilerplate.
Macro helper example
#define C_LINKAGE_BEGIN extern "C" {
#define C_LINKAGE_END }Sample header guard with conditional extern "C"
#ifndef _C_FUN_H_
#define _C_FUN_H_
#ifdef __cplusplus
extern "C" {
#endif
void cfun();
#ifdef __cplusplus
}
#endif
#endif // _C_FUN_H_Key takeaways
Understanding extern "C" prevents subtle linkage errors when mixing C and C++ code. Keep #include directives outside the linkage block, use __cplusplus to guard the specification, and limit the block to functions, variables, or function‑type declarations that need C linkage.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
