Function Prototypes and Headers in C++
Each piece may call functions that are defined somewhere else.
Why Linkage Needs Special Attention
Most real programs are built from several pieces, such as separate source files and libraries. Each piece may call functions that are defined somewhere else. Something has to connect every call in one piece to the function definition in another piece. That connection is governed by linkage, which describes how functions and variables are accessed across different source files and libraries.
When a program is built from several pieces, the linker has to connect each call to the function defined elsewhere. Whether two pieces of code connect smoothly depends on the linkage conventions the languages use. This is why linkage needs special attention as soon as C and C++ code are mixed in one program.
C and C++ can be implemented to use different linkage conventions, and often are. The most basic reason is C++'s greater emphasis on type checking. A practical reason is that C++ supports overloading, which lets a program contain two global functions with the same name, such as two functions both called open(). C does not allow this, so the linker has to be able to tell these cases apart in a way that reflects each language's rules.
How the Linker Matches Calls to Definitions
Think of the linker as a matcher. It receives pieces of compiled code, and for each call it looks for the definition that the call refers to. A call in a C fragment and a call in a C++ fragment can both target the same function, such as the square-root function that takes and returns a double. The declaration is the point where the two languages agree on how that function is linked.
The diagram shows the role of the declaration. Once the declaration is in place, sqrt(double) can be called from either a C or a C++ code fragment. The definition of sqrt(double) can also be compiled either as a C function or as a C++ function. The linker can then connect both kinds of call to that one definition, because the declaration fixed the linkage both sides rely on.
- The declaration gives sqrt(double) C linkage so the C++ call below can be connected to a definition compiled as C.
- The function
half_rootis ordinary C++ code and needs no linkage specification of its own.
Tracing one call from C++ to a C function
A C++ fragment calls sqrt(double), and the definition of sqrt(double) was compiled as a C function. Trace how the call is connected.
- 1Step 1: the declaration
The C++ fragment sees extern "C" double sqrt(double); so the call is made with C linkage.
- 2Step 2: the call
The call in
half_rootrefers to sqrt(double) by its declared name and signature. - 3Step 3: the definition
The definition was compiled as a C function, so its linkage matches the declaration.
- 4Step 4: the linker
The linker connects the call to the definition, because both sides agree on how the function is linked.
The C++ call reaches the C definition. The declaration was the agreement point that made the connection possible.
Reading the extern C Declaration
To call a C function from a C++ program fragment, declare it with extern "C". The same declaration form also gives a C++ function C linkage, so that it can be called from a C program fragment. Each part of the declaration has a separate job, as the anatomy below shows.
Read left to right, the declaration first says that the function has C linkage, which is the part that controls how it is linked. The return type double, the name sqrt, and the parameter list (double) then describe the function itself. The linkage part and the signature part are separate. Changing the linkage convention does not by itself change what arguments the function accepts or what it returns.
What a Linkage Specification Leaves Unchanged
A linkage specification changes how a function is linked. It does not change how the function is checked. The C++ rules for function calls and argument checking still apply to a function declared with extern "C". This is the most common misunderstanding about the feature, so it is worth testing your own expectation before reading the answer.
What do you think happens?
A function is declared extern "C" and then called with arguments of the wrong type. Does the extern "C" declaration relax the C++ type checks for that call?
Reveal answer
No, the C++ checks for function calls still apply
A linkage specification affects linkage only. It changes how the function is connected to its definition, while the C++ rules for function calls and argument checking are unchanged.
Overloading Under C and C++ Rules
The difference between the two languages becomes clearer when the same function name is considered under each set of rules. In C, a given name can refer to only one global function of that name in a scope. In C++, overloading allows several global functions to share a name, so the linker must account for more than the name alone when it matches a call to a definition.
This is why a C-linkage function is restricted. Only one function of a given name in a scope can have C linkage, because C does not allow overloading. If a C++ program contains two overloads with the same name, such as two functions both called open(), they cannot both be given C linkage in that scope. The overloads still exist in C++, but the C linkage rule cannot match two same-named functions under C's one-name-per-function convention.
Mistakes at the C and C++ Boundary
Common mistake Declaring a C function in a C++ program without extern "C"
What it looks likeA C++ file calls sqrt(double) through a plain declaration, while the definition was compiled as a C function.
Why it failsWithout the linkage specification, the C++ call is not connected to the C definition under the agreed convention, so the linker may fail to connect them.
Do this insteadDeclare the C function with extern "C" so that the call and the definition agree on linkage.
Common mistake Assuming extern "C" relaxes argument checking
What it looks likeA function declared extern "C" is called with arguments of the wrong type and the programmer expects the call to be accepted.
Why it failsA linkage specification affects linkage only. The C++ rules for function calls and argument checking still apply.
Do this insteadKeep the argument types correct under C++ rules. Use linkage specifications only for linkage.
Common mistake Expecting two C++ overloads to both have C linkage
What it looks likeTwo C++ functions both named open are each declared with C linkage in the same scope.
Why it failsOnly one function of a given name in a scope can have C linkage, because C does not allow overloading.
Do this insteadGive C linkage to only one function of that name in the scope, and keep other overloads on C++ linkage.
Common mistake Forgetting that a C++ function must be declared with extern "C" before a C fragment can call it
Treat the declaration as the agreement point between the two languages. Whenever a function must cross the boundary between C and C++, make sure its declaration carries the linkage specification that both sides rely on. Linkage is one part of converting a C program to C++, and it deserves deliberate attention whenever the two languages meet.
Checking Your Understanding
A C++ program contains two global functions, both named open. You want one of them to be callable from a C fragment. Can both of them be given C linkage in the same scope, and why or why not?
Hints
- Recall what C says about two global functions that share one name in a scope.
- The source says only one function of a given name in a scope can have C linkage.
Explain in your own words what a linkage specification changes and what it leaves alone, using the sqrt example from this article.
Hints
- Separate the part of the declaration that controls linkage from the part that describes the signature.
- Think about what still happens when a C++ caller passes an argument of the wrong type.
Key Takeaways
- Linkage describes how functions and variables are accessed across source files and libraries, and the linker must connect each call to a definition.
- C and C++ can use different linkage conventions, mainly because C++ emphasizes type checking and supports overloading.
- To call a C function from C++, or to let a C++ function be called from C, declare it with extern "C"; the declaration is where both languages agree on linkage.
- A linkage specification changes linkage only. C++ rules for function calls and argument checking still apply, and only one function of a given name in a scope can have C linkage.