Why Use extern "C" When Linking C and C++
The extern "C" linkage specification exists in C++ to
prevent name mangling, allowing the C++ linker to resolve function
symbols generated by a C compiler. In mixed-language programming, C and
C++ use different conventions for generating symbol names in compiled
object files. By applying extern "C" to a declaration, you
instruct the C++ compiler to adhere to standard C linkage conventions,
enabling compiled C and C++ object files to successfully link together
without unresolved symbol errors.
The Mechanism of Name Mangling
C++ introduces features that C does not have, such as function overloading, classes, and namespaces. Because multiple functions can share the same name with different parameter types in C++, the compiler must generate a unique identifier for every variation.
To achieve this, the C++ compiler alters function names in the object file's symbol table by encoding information about the function's namespace, class scope, and argument types into the final symbol. This process is known as name mangling (or name decoration). For example, a function declared as:
void print(int x);might be transformed by a C++ compiler into a mangled symbol such as
_Z5printi.
In contrast, the C language does not support function overloading. As
a result, C compilers do not mangle function names; the function
print is exported to the object file symbol table directly
as print (or sometimes _print, depending on
the platform).
The Linker Mismatch
When compiling separate translation units into object files
(.o or .obj), the compiler assumes that
external references will be resolved later by the linker.
If a C++ file calls a C function declared as:
int add(int a, int b);the C++ compiler defaults to C++ linkage and emits an external
reference for a mangled name, such as _Z3addii. When the
linker attempts to join the C++ object file with the compiled C object
file, it searches for _Z3addii. However, the C object file
only exports the unmangled name add. Because the symbols do
not match, the linker fails with an "undefined reference" error.
How extern "C"
Solves the Problem
The extern "C" keyword instructs the C++ compiler to
treat the enclosed declarations as having C linkage. This disables name
mangling and ensures that the function name appears in the symbol table
in plain C format.
When you declare the function as:
extern "C" int add(int a, int b);the C++ compiler emits an unresolved symbol simply for
add, which matches the symbol exported by the C object
file, allowing the linker to successfully bind them.
Common Usage in Header Files
To allow a header file to be included by both C and C++ source files
without syntax errors, the standard practice uses the
__cplusplus preprocessor macro:
#ifndef MY_HEADER_H
#define MY_HEADER_H
#ifdef __cplusplus
extern "C" {
#endif
int add(int a, int b);
void process_data(const char* input);
#ifdef __cplusplus
}
#endif
#endifBecause C compilers do not recognize the extern "C"
syntax, the #ifdef __cplusplus check hides the linkage
specification from pure C compilations while ensuring that C++ compilers
parse the declarations with C linkage.