Why extern "C"?

C++ in order to support function overloading, it uses name mangling which changes the name of the functions present in the obj file. An example readout with the nm utility for the obj file generated for CPP code is given below:

$ nm cpp.o

                U _GLOBAL_OFFSET_TABLE_
00000000000000d3 t _GLOBAL__sub_I_main
0000000000000000 T main
                U _Z3addii
                U _Z8multiplyii

It can be seen that the functions, add and multiply are altered by adding some post fix and pre-fix information.

$ nm c.o

                U add
00000000000000d3 t _GLOBAL__sub_I_main
0000000000000000 T main
                U multiply
    int add(int x, int y);
    int multiply(int x, int y);

When using legacy libraries C in CPP code, the header files cannot be included directly. If done, the linker tries to find the functions of the name _Z8multiplyii in the obj file which has only the name multiply causing the unresolved symbol error. This can be solved by including the legacy library within extern "C", which avoids name mangling. The complete code should look like follows:

#include <iostream>
extern "C" {
    #include "legacy_c_lib.h"
}

When code is compiled with this feature, it retains the original names of the function in the obj file.

It should be noted that any code who naming conventions need to be preserved should be written with the extern "C" block.

An alternative way to read the symbol table is with: readelf -s cpp_prog.o

Written on July 13, 2019