I often see the following code in C
header files:
#ifdef __cplusplus
extern "C" {
#endif
......
#ifdef __cplusplus
}
#endif
What does it mean? Since there is __cplusplus
marco, it must be related to C++
compilation. Let’s see a simple program (print.c
):
$ cat print.c
#include <stdio.h>
void print(void)
{
printf("Hello world!\n");
}
Use gcc
to generate object file:
$ gcc -c print.c
$
Then create a main.cpp
file which calls print()
in its main()
function:
$ cat main.cpp
extern void print(void);
int main(void)
{
print();
return 0;
}
Compile main.cpp
and link with print.o
:
$ g++ main.cpp print.o
/tmp/cc60fu19.o: In function `main':
main.cpp:(.text+0x5): undefined reference to `print()'
collect2: error: ld returned 1 exit status
It is weird, right? the print()
function must be defined in print.o
, why can’t g++
find it? Let’s do a simple magic, add "C"
in extern void print(void);
:
$ cat main.cpp
extern "C" void print(void);
int main(void)
{
print();
return 0;
}
Try compile main.cpp
again:
$ g++ main.cpp print.o
$ ./a.out
Hello world!
It is OK now! The root cause is related to name mangling. To be simplified, when compile C++
code, the names of functions, global variables, etc will be modified, not the same as original format. While compile C
code, this won’t happen. The function of extern "C"
is to tell C++
compiler search the original name, not the mangled ones. To get a sense of name mangling
, you can check the print()
name in object file:
$ readelf -s print.o | grep print
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS print.c
9: 0000000000000000 17 FUNC GLOBAL DEFAULT 1 print
Then use g++
to compile print.c
, and check function name again:
$ g++ -c print.c
$ readelf -s print.o | grep print
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS print.c
9: 0000000000000000 17 FUNC GLOBAL DEFAULT 1 _Z5printv
You can see the print()
function name is actually _Z5printv
when use g++
to generate the object file.
References:
Why do we use extern “C”?;
In C++ source, what is the effect of extern “C”?.