Fundamentals 16 min read

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.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Why You Shouldn’t Put #include Inside extern "C" and How to Use It Correctly

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
}
#endif

This 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

C++C interoperabilityname manglingheader filesextern Clinkage
Liangxu Linux
Written by

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.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.