Calling C Code from C++ With ‘extern “C”‘

Contents

Now and then we have the need to call functionality that was written in C from our C++ programs. For that, we need to use and understand extern "C".

The probably easiest way to use C functionality in a C++ program is to simply compile the C code as C++ code. This will, however, not work reliably. While C++ is based on C, the two languages have their differences. They have even diverged insofar that modern C has features that are not valid C++.

So, we have to compile the C code as C, and the C++ code as C++. Some compilers do this automatically by file extension, others need to be told explicitly. The actual issue is to link the compiled C and C++ object files together.

Linking and name-mangling

Very broadly speaking, the linker has to resolve symbols that are referenced in one or more translation units with their definition in another translation unit. Those symbols can be variable names or function names. For simplicity, let’s assume we have a function void foo(int) that has been defined in one source file and gets called in another source file.

In C, the compiler generates a simple symbol foo for that function – this is defined in the C standard. In C++, we can have much more than one function named foo: we have different namespaces, classes with member functions, and overloaded functions that take different parameters. Therefore, the C++ compiler can not simply create a symbol foo. It has to generate names that contain all that information. The process is called name mangling and is not standardized.

Let’s assume, foo is our C function, that we want to call from main in our C++ program:

//main.cpp 

#include "foo.h"
int main() {
  foo(22);
}
//foo.h
void foo(int);
#include <stdio.h>
//foo.c
void foo(int i) {
  printf("%i\n", i);
}

When we compile the whole thing, the linker will give us an error: The C++ compiler will see the declaration of void foo(int) and the call to that function and generate a mangled name, say, void@foo(int). The C compiler will simply generate the symbol foo. The linker will, therefore, complain that it can not find void@foo(int), because that symbol simply does not exist.

extern “C” to the rescue

To solve the above problem, the C++ standard allows declaring things with language linkage. Besides the default C++ linkage, we can explicitly declare things to have “C” linkage. Declaring foo with “C” linkage will cause the C++ compiler to refer to the name foo instead of the mangled name. We can declare single entities to have “C” linkage as follows:

extern "C" void foo(int);

More convenient is to declare a whole list of declarations to be of “C” linkage:

extern "C" {
  void foo(int);

  //more declarations...
}

Note that this is strictly C++ code, as C does not allow the language linkage specification. So, how do we bring all this together without having to rewrite all the C declarations with “C” linkage for the C++ compiler?

The wrong solution

What we see often is, that developers start to alter the C headers as follows:

//foo.h
#ifdef __cplusplus
extern "C" {
#endif

  void foo(int);

#ifdef __cplusplus
} //end extern "C"
#endif

This will work as intended, as the extern "C" will be only visible to the compiler. However, it is more than ugly. It infests plain C headers with C++ specific code, which is not desirable. We write that code in C for a reason, usually because it is a library that we’d like to be reused in C programs.

We will have to add these two blocks to any C header that might be used from our C++ program, which may be quite a lot. The C headers may include each other, and while the compiler is OK with encountering several nested levels of extern "C", that’s a lot of noise.

The other argument against this practice is that it may not be our responsibility to maintain those C headers. We might not even be able to change them in the future.

The correct solution

Since #include is a simple text replacement by the preprocessor, we can put the extern "C" declaration in our C++ code, where it belongs:

//main.cpp

extern "C" {
  #include "foo.h"
}

int main() {
  foo(22);
}

This way, everything inside the header, including the indirectly included declarations in other C headers, appear inside the extern "C" declaration.

Caveats

There may be concerns that this looks unfamiliar or even ugly in the C++ code. However, it is still nicer than having the declaration surrounded by #ifdefs in all our C headers. It also may lead to hard-to-find linker errors when we forget to surround a C header include with the extern "C" linkage declaration.

Both issues should be minor concerns though if we encapsulate and restrict the use of the C functionality. If we truly have to use the C headers throughout our code base, there’s the option to write a C++ wrapper header for C headers:

//foo_for_cpp.h
extern "C" {
  #include "foo.h"
}
//main.cpp

#include "foo_for_cpp.h"

int main() {
  foo(22);
}
Previous Post
Next Post

10 Comments


  1. Now I see why you didn’t include specific commands using the GNU C compiler for “The Correct Solution”.

    $ g++ -o yourprogram somecode.o othercode.o
    /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/Scrt1.o: in function _start':
    (.text+0x20): undefined reference to
    main’
    collect2: error: ld returned 1 exit status

    It doesn’t compile.
    I am beginning to think that it is not possible to call a C function from a C++ main using the GNU C compiler.

    Reply

    1. I call C functions from C++ code and it compiles every day. Your linker error seems to be something different. According to the error message, neither of the two object files contains a main function. If you show the actual sources that resulted in those object files, I can do more than guesswork as to why the linker doesn’t find main.

      Reply

  2. Hi Arne, thanks so much for writing.

    I am trying to include two C headers to my C++ program that have the same name, types, and functions (they are the same utility with different parameters).

    With only one instance of the C code in use, I used the extern “C” {#include “foo.h”} in my C++ .cpp file. Now that I try to include the second, there are name conflicts. Note, I have individual cpp files wrapping use of the each C-code utility.

    I implemented your foo_for_cpp.h solution to no avail.

    To my question: Is it possible to create aliases for the C types and functions in foo_for_cpp.h to avoid the conflicts?

    Sorry if my vocab isn’t quite right; I’m not a professional.

    Respectfully, John

    Reply

    1. Hi John,
      I am afraid there is no easy solution to that. If the two headers are header only (i.e. all functions are inlined, there are no .c source files having definitions), you might get away with putting the includes in anonymous namespaces and include only one of those headers in any .cpp source file. That way, the symbols in those headers are only visible locally in the respective .cpp file.

      If that is not the case, i.e. there are definitions in .c source files, this is not possible due to linking rules: There will be two different definitions of the same function in two translation units, which violates the One Definition Rule and makes your program invalid and undefined behavior.

      Reply

  3. So let us change our implementations…

    Reply

  4. The last solution is really my preferred one (through I am fine with the first).
    If I have learned one thing over the years, then its this: Give a developer the opportunity to create a bug by forgetting something about the system and he will do it.
    Forcing developers to include extern “C” around all includes they think come from C libraries will guarantee that.

    Reply

  5. This is extremely bad advice.

    Your C headers include C standard library headers, right? Not in C++: those are the C++ standard library headers with the same name. And you’re including them in an extern “C” block.

    Guess what? Now you have UB, or (if you’re lucky) compile errors.

    And it gets worse: some non-stdlib C headers provide additional interfaces when included in C++. You just broke those too. Maybe you’ll get a build break because you put a template in an extern “C” block. Maybe you’ll get a link error. But this will bite you eventually.

    The right thing is the traditional #ifdef __cplusplus / extern “C” { dance, and make sure you only wrap the extern “C” around your own code, not your #includes.

    (For bonus reading, search for Chesterton’s Fence.)

    Reply

    1. I disagree. My C headers usually do not include C standard library headers or similar. A C library that does this in its API headers cannot be used from C++ code without modification. That means the author of those headers has to explicitly prepare them for reuse in C++-land. They then have the choice to put the #ifdef... extern "C" everywhere or turn the default around: If you use headers that behave differently in C++ code, prepare your C API for C++ reuse by protecting that different behavior with #ifdef __cpluplus / extern "C++".

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *