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

#endif

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