Guide
extern c
相比C语言,C++支持函数重载、类、模版等各种特性,如果C++的符号修饰仍按照C那样直接使用对应名称,虽然可读性很好,却不可避免的会出现各种错乱,于是C++符号修饰别名(mangled name)被设计出来, 用来解决上述问题,然而修饰规则取决于编译器实现,没有统一标准,比如gcc、msvc就各有一套,但好在都提供了相应接口进行解析(demangle),这里有个网站demangler可以在线解析
c++ function: managled names
c function: unmangled namesextern c
告诉c++编译器将f_int,f_float
视为c函数,使用 unmangled names(修饰名称)
managled/unmangled names
a.cpp
1 | void f() {} |
Compile with GCC 4.8 Linux ELF output:
g++ -c a.cpp
Decompile the symbol table:
readelf -s a.o
output
Num: Value Size Type Bind Vis Ndx Name
8: 0000000000000000 6 FUNC GLOBAL DEFAULT 1 _Z1fv
9: 0000000000000006 6 FUNC GLOBAL DEFAULT 1 ef
10: 000000000000000c 16 FUNC GLOBAL DEFAULT 1 _Z1hv
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z1gv
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND eg
managled names:
_Z1fv,_Z1hv,_Z1gv
forf,g,h
unmangled names:ef,eg
unmanagle them
c++filt _Z1fv
f()
c++filt _Z1hv
h()
c++filt _Z1gv
g()
extern C中错误用法
It becomes obvious that any C++ feature that requires name mangling will not work inside extern C:
error.cpp
1 | extern "C" { |
compile and generate errors
g++ -c error.cpp
error.cpp:5:17: error: conflicting declaration of C function ‘void f(int)’
void f(int i);
^
error.cpp:4:10: note: previous declaration ‘void f()’
void f();
^
error.cpp:9:5: error: template with C linkage
template <class C> void f(C i) { }
^
So you will need extern "C"
both when calling:
- C from C++: tell
g++
to expect unmangled symbols produced bygcc
- C++ from C: tell
gcc
to use unmangled symbols produced byg++
cpp中使用c方法
code
main.cpp
1 |
|
c.h
1 |
|
c.c
1 |
|
OK
compile main.cpp
g++ -c -o main.o -std=c++98 main.cpp
readelf -s main.o
10: 0000000000000000 46 FUNC GLOBAL DEFAULT 1 main
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __assert_fail
使用c++编译器,extern c告诉c++编译器
f
是一个c函数,使用unmanagled namef
compile c.c
gcc -c -o c.o -std=c89 c.c
readelf -s c.o
8: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f
使用c编译器,对于c函数生成unmanagled name
f
link main.o and c.o
g++ -o main.out main.o c.o
./main.out
OK.
Error
Without extern "C"
the link fails with:
main.cpp:6: undefined reference to `f()'
compile main.cpp
g++ -c -o main.o -std=c++98 main.cpp
readelf -s main.o
10: 0000000000000000 46 FUNC GLOBAL DEFAULT 1 main
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z1fv
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __assert_fail
因为没有extern c,所以g++编译器将f看做是c++函数,使用managled name
_Z1fv
compile c.c
gcc -c -o c.o -std=c89 c.c
readelf -s c.o
8: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f
使用c编译器,对于c函数生成unmanagled name
f
link main.o and c.o
g++ -o main.out main.o c.o
main.o: In function `main':
main.cpp:(.text+0x5): undefined reference to `f()'
collect2: error: ld returned 1 exit status
link失败,因为c++编译器需要managled name
_Z1fv
,然而c编译器生成了unmanagled namef
c中使用cpp方法
code
main.c
1 |
|
cpp.h
1 |
|
cpp.cpp
1 |
|
OK
compile main.c
gcc -c -o main.o -std=c89 -Wextra main.c
readelf -s main.o
10: 0000000000000000 94 FUNC GLOBAL DEFAULT 1 main
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f_int
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __assert_fail
13: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f_float
使用c编译器,将
f_int,f_float
视作c函数,使用unmanagled namef_int,f_float
compile cpp.cpp
g++ -c -o cpp.o -std=c++98 cpp.cpp
readelf -s cpp.o
9: 0000000000000000 15 FUNC GLOBAL DEFAULT 1 _Z1fi
10: 000000000000000f 32 FUNC GLOBAL DEFAULT 1 _Z1ff
11: 000000000000002f 23 FUNC GLOBAL DEFAULT 1 f_int
12: 0000000000000046 31 FUNC GLOBAL DEFAULT 1 f_float
使用c++编译器,
extern c
告诉c++编译器将f_int,f_float
视作c函数,使用unmanagled namef_int,f_float
link main.o and cpp.o
g++ -o main.out main.o cpp.o
./main.out
OK.
Error
Without extern “C” it fails with:
main.c:6: undefined reference to `f_int'
main.c:7: undefined reference to `f_float'
compile main.c
gcc -c -o main.o -std=c89 -Wextra main.c
readelf -s main.o
10: 0000000000000000 94 FUNC GLOBAL DEFAULT 1 main
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f_int
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __assert_fail
13: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f_float
使用c编译器,将
f_int,f_float
视作c函数,使用unmanagled namef_int,f_float
compile cpp.cpp
g++ -c -o cpp.o -std=c++98 cpp.cpp
readelf -s cpp.o
9: 0000000000000000 15 FUNC GLOBAL DEFAULT 1 _Z1fi
10: 000000000000000f 32 FUNC GLOBAL DEFAULT 1 _Z1ff
11: 000000000000002f 23 FUNC GLOBAL DEFAULT 1 _Z5f_inti
12: 0000000000000046 31 FUNC GLOBAL DEFAULT 1 _Z5f_floatf
使用c++编译器,因为没有
extern c
,c++编译器将f_int,f_float
视作c++函数,使用managled name_Z5f_inti,_Z5f_floatf
link main.o and cpp.o
g++ -o main.out main.o cpp.o
link失败,因为c编译器需要unmanagled name
f_int,f_float
,然而c++编译器生成了managled name_Z5f_inti,_Z5f_floatf
Reference
History
- 20181226: created.