Concepts / Function Prototypes and Headers in C++

Function Prototypes and Headers in C++

Each piece may call functions that are defined somewhere else.

  • Programming

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.

C fragmentcalls sqrt(double)Declarationextern C doublesqrt(double)Definitionsqrt(double) compiled as Cor C++Linkerconnects each call to thedefinitionC++ fragmentcalls sqrt(double)declaresdeclaresagreed linkageprovides definitionnames the function
Which declarations and definitions must agree so that calls from both a C fragment and a C++ fragment reach the same function?

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.

cpp
Notes on the code
  • The declaration gives sqrt(double) C linkage so the C++ call below can be connected to a definition compiled as C.
  • The function half_root is ordinary C++ code and needs no linkage specification of its own.
Worked example

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.

  1. 1
    Step 1: the declaration

    The C++ fragment sees extern "C" double sqrt(double); so the call is made with C linkage.

  2. 2
    Step 2: the call

    The call in half_root refers to sqrt(double) by its declared name and signature.

  3. 3
    Step 3: the definition

    The definition was compiled as a C function, so its linkage matches the declaration.

  4. 4
    Step 4: the linker

    The linker connects the call to the definition, because both sides agree on how the function is linked.

Result

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.

externintroduces a linkagespecificationCrequests C linkagedoublereturn typesqrtfunction name(double)parameter type, part of thesignature
Which part of extern "C" double sqrt(double); requests the linkage convention, and which parts make up the function's signature?

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?

  • Yes, C linkage turns off argument checking

  • No, the C++ checks for function calls still apply

Reveal answer
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.

Global functionssharing a nameat most oneGlobal functionssharing a nameseveral, throughoverloadingLinker matches bythe nameLinker matches bymore than the name alone
How many global functions may share one name in each language, and what the linker must consider when it matches calls?

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 like

    A C++ file calls sqrt(double) through a plain declaration, while the definition was compiled as a C function.

    Why it fails

    Without 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 instead

    Declare 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 like

    A function declared extern "C" is called with arguments of the wrong type and the programmer expects the call to be accepted.

    Why it fails

    A linkage specification affects linkage only. The C++ rules for function calls and argument checking still apply.

    Do this instead

    Keep 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 like

    Two C++ functions both named open are each declared with C linkage in the same scope.

    Why it fails

    Only one function of a given name in a scope can have C linkage, because C does not allow overloading.

    Do this instead

    Give 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

Best practice

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

MEDIUM

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

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.

Related concepts

More concepts starting with F