Mixing C and C++ code

C and C++ are two closely related programming languages. Therefore, it may not come as a surprise to you that you can actually mix C and C++ code in a single program. However, this doesn’t come automatically when you write your code the normal way. In this blog post, I will describe what makes it possible to mix the two languages and how to achieve that in code.

C and C++ linkage

When you compile a source file, the function names are mangled. Name mangling is the process that turns each function name into a unique name (identifier) so that during linking the linker can correctly link each function call to the correct function definition. In C and C++, the names are mangled in different ways. If you write normal C++ code and try to include the header in a C program, the linker will complain that the C++ function you are calling is undefined. Therefore, we must tell the C++ compiler that a function will be used in a C program and it should mangle the name in the C way. The way to do it is to use extern "C" when declaring the functions in C++.

// both ways are OK!
extern "C" void hello1();
extern "C" {
    void hello2();
}

void hello1()
{
    //...
}

void hello2()
{
    //...
}

Now if we compile it and inspect the names, we get the mangled names _hello1 and _hello2.

$ g++ -c c_linkage.cc
$ nm c_linkage.o
0000000000000000 T _hello1
0000000000000010 T _hello2

If you don’t use extern "C", you would get mangled names __Z6hello1v and __Z6hello2v.

$ g++ -c cpp_linkage.cc
$ nm cpp_linkage.o
0000000000000000 T __Z6hello1v
0000000000000010 T __Z6hello2v

As you can see, extern "C" lets the compiler mangle the name differently.

Mixing the code

Now that we know how to control name mangling, let’s see how we can actually call C++ function from C. Basically, you have to make sure that when you compile your C++ code, the compiler sees extern "C" around your function declaration. However, when you compile the C part, the function declaration should appear as normal because, from the C compiler’s point of view, the function is just a normal C function. Of course one way to do it is to create two separate header files. A better way to do it is to use a handy macro,

#ifdef __cplusplus
extern "C" {
#endif
// your function declarations...
#ifdef __cplusplus
}
#endif

The __cplusplus macro is only defined by C++ compilers. Therefore, you can include this header file in both the C and C++ code.

It also works the other way around. When you define the function in C and call it in C++, the C compiler will compile as normal and the C++ compiler will know that the function being called has C name mangling.

Conclusion

In conclusion, I described the difference between C and C++ linkage and how you can successfully mix C and C++ code by controlling the linkage. There are many cases mixing the two is necessary. For example, the CUDA compiler nvcc by default follows C++ linkage. Therefore, you must change it to C linkage in order to mix C and CUDA code. I hope you find this post useful if you are trying to mix the two languages for whatever use case you might have.

References

 
comments powered by Disqus