Memory Management When Converting from malloc and free to new and delete
When a C program is converted to C++, or when C and C++ code have to work together in one program, the two languages meet at the linker.
Why Linkage Matters at the C and C++ Boundary
When a C program is converted to C++, or when C and C++ code have to work together in one program, the two languages meet at the linker. The linker is the tool that connects a call made in one compiled piece of code to the function that is defined in another piece. Whether that connection works smoothly depends on the linkage conventions each language uses, and the two languages do not always use the same ones. This article explains why that is so and how the extern "C" declaration bridges the gap.
What Linkage Means
Linkage describes how functions and variables are accessed across different source files and libraries. When a program is built from several pieces, each call in one piece has to be connected to the function defined in another piece.
Think of a program built from two files. One file calls a function named sqrt, and a different file, or a library, contains the definition of sqrt. Nothing in the calling file contains the body of that function. The linker's job is to match the call with the definition. Linkage is the set of rules that makes that matching possible, so a call in one piece can find the right function in another.
Why C and C++ Link Differently
C and C++ can be implemented to use different linkage conventions, and in practice they often are. The most basic reason is that C++ places a greater emphasis on type checking. A second, practical reason is that C++ supports overloading.
Overloading lets a program contain two global functions with the same name. The source's example is two functions that are both called open(). C does not allow this. Because C++ allows it, the linker has to be able to tell the two functions apart in a way that reflects the rules of the language. Since C has no such need, C linkage can treat a name more simply. This difference is why linkage needs special attention whenever C and C++ code are mixed.
Reading an extern C Declaration
To call a C function from a C++ program fragment, you declare it with extern "C". The same declaration form also gives a C++ function C linkage, so that the function can be called from a C program fragment. The source's standard example is the declaration of the square-root function, which takes a double and returns a double.
- extern "C" is the linkage specification: it asks for C linkage for this declaration
- double (first) is the return type
- sqrt is the function name
- (double) is the parameter list, which takes one double argument
- The trailing semicolon ends the declaration
Reading the declaration from left to right: extern "C" is the part that changes the linkage. The double before the name is the return type, sqrt is the name, and the parentheses hold the parameter list. Everything after extern "C" is an ordinary function declaration. The linkage specification is added to the declaration; it does not replace the function's type information.
How Overloading Changes the Picture
The difference between the two languages is easiest to see by comparing the same function name under each set of rules. Under C rules, one name refers to one global function in a scope, so the name alone is enough for the linker to find it. Under C++ rules, several overloads can share the name open, and the linker must distinguish them. The diagram below shows the two situations side by side. The exact internal naming scheme a C++ compiler uses is not described in the available material, so the diagram shows only the distinction itself.
What a Linkage Specification Changes
A linkage specification changes how a function is linked. It does not change how the function is checked. This is the most important point to remember. A function declared with extern "C" still follows the C++ rules for function calls and argument checking, and it still takes part in overload resolution at the call site.
| Aspect | Affected by extern "C"? | What it means |
|---|---|---|
| How the function is linked | Yes | The declaration gives the function C linkage, so C and C++ code can connect to it |
| Argument type checking | No | C++ checking rules still apply to every call |
| Overload resolution at the call site | No | C++ still chooses among overloads by the C++ rules |
| Calling it from a C++ fragment | Enabled | The declaration lets C++ code call a C function |
| Calling it from a C fragment | Enabled | The same form lets a C++ function be called from C code |
What a linkage specification alters and what it leaves alone
The pipeline shows the division of labor. Each compiler handles its own language, and the linker's task is to join the compiled pieces. The declaration with extern "C" in the C++ file is what tells that side of the program which linkage convention to expect for the C function, so the call and the definition can meet at the linker.
Does the Declaration Relax the Checks?
What do you think happens?
A function is declared with extern "C", and then it is called with arguments of the wrong type. Does the extern "C" declaration relax the C++ type checks for that call?
Reveal answer
No. The linkage specification affects linkage only. The C++ rules for function calls and argument checking still apply.
Extern "C" changes the linkage convention, which is how the function is connected by the linker. It does not change how the function's arguments are checked when the function is called.
Worked Example: Calling sqrt from Both Languages
Declaring sqrt so both C and C++ can use it
The square-root function takes and returns a double. How can it be called from a C++ fragment and also be made available to a C fragment?
- 1Declare the function with extern "C"
The declaration extern "C" double sqrt(double); gives the function C linkage. This is the form the source uses for the standard square-root example.
- 2Call it from a C++ fragment
With the declaration in place, sqrt(double) can be called from a C++ code fragment. The declaration tells the C++ side which linkage convention the function follows.
- 3Call it from a C fragment
The same declaration allows sqrt(double) to be called from a C code fragment, because the function has C linkage.
- 4Compile the definition either way
The definition of sqrt(double) can be compiled either as a C function or as a C++ function. The declaration is the point where the two languages agree on how the function is linked.
The extern "C" declaration is the agreement point: one function with C linkage can be called from both a C and a C++ fragment, and the declaration does not change the argument checking the function receives.
Common Mistakes at the C and C++ Boundary
Common mistake Assuming extern "C" turns off type checking
What it looks likeA function declared with extern "C" is called with an argument of the wrong type, and the programmer expects the compiler to accept it.
Why it failsA linkage specification affects linkage only. The C++ rules for function calls and argument checking still apply.
Do this insteadKeep the call's arguments matching the declared parameter types. The extern "C" declaration only controls how the function is linked.
Common mistake Expecting a link error to appear only at the call site
What it looks likeA C header is included in C++ code without extern "C", and the program fails to link even though the code looks correct.
Why it failsWithout the linkage specification, the C++ side expects C++ linkage for the function, so the linker may not find a matching C definition.
Do this insteadWrap the C declarations in an extern "C" block where the C++ code includes them, so the function is declared with C linkage.
Common mistake Declaring two C-linkage functions with the same name in one scope
What it looks likeTwo overloads of open are both given C linkage in the same scope.
Why it failsC does not allow overloading, and only one function of a given name in a scope can have C linkage.
Do this insteadGive the C-linkage function a single name in that scope, and use distinct names for functions that need separate definitions.
Common mistake Treating linkage as a fix for all conversion problems when it only addresses how functions are connected
Edge Case: One C-Linkage Name per Scope
Only one function of a given name in a scope can have C linkage, because C does not allow overloading. This means that even in C++, a name that is meant to be called from C cannot be overloaded with several C-linkage versions in the same scope. The restriction follows from the C rule being applied to that name, not from any change in how the call is checked.
Practice: Placing the Wrapper
A C library header declares int add(int a, int b); and a C++ file includes that header directly. Where should the extern "C" wrapper go, and which part of the code does it change?
Hints
- Ask which side of the boundary needs to know that add has C linkage.
- Remember that the wrapper changes linkage, not the parameter types or how the call is checked.
- The wrapper belongs around the declaration that the C++ code sees when it includes the C header.
Summary of Linkage at the Boundary
- 1C and C++ can use different linkage conventions, mainly because C++ emphasizes type checking and supports overloading.
- 2A declaration with extern "C" gives a function C linkage, so C++ code can call a C function and C code can call a C++ function declared the same way.
- 3A linkage specification changes how a function is linked, but not how it is checked, so C++ argument checking and overload resolution still apply.
- 4Only one function of a given name in a scope can have C linkage, because C does not allow overloading.
- 5Missing or misplaced extern "C" can cause link errors when C code is included in C++.
At a glance
- C and C++ can use different linkage conventions, mainly because C++ emphasizes type checking and supports overloading.
- extern "C" declares a function with C linkage so that C and C++ fragments can call it.
- A linkage specification changes linkage only; C++ type checking and overload resolution still apply.
- Only one function of a given name in a scope can have C linkage, since C does not allow overloading.
- Missing or misplaced extern "C" declarations are a common cause of link errors when C code is used in C++.