C++中extern "C"的设立动机是实现C++与C及其它语言的混合编程。
C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。
例如,假设某个函数的原型为:void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字为_foo,
而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。
1.如果要在C++程序中调用C语言写的函数, 在C++程序里边用 extern "C" 修饰要被调用的这个C程序,告诉C++编译器此函数是C语言写的,是C语言编译器生成的,调用他的时候请按照C语言习惯传递参数等。例子如下:
首先我们有C语言制作的函数库:libmyclib.a (参考gcc生成静态库和动态库)[1]
gcc -c clib_hello.c clib_math.c
ar -r libmyclib.a *.o
//clib_hello.c #include <stdio.h> void sayHello(void) { printf("clib hello!\n"); } //clib_math.c int add(int va ,int vb) { return va+vb; } //clib_hello.h extern void sayHello(void); //clib_math.h extern int add(int va ,int vb);
然后,cpp编译链接c函数库
g++ cppMain.cpp libmyclib.a -o democpp
【或者:g++ cppMain.cpp -L. -lmyclib】
//cppMain.cpp #include <iostream> using namespace std; #if 0 extern "C"{////可以,但不推荐。 《华为技术有限公司c语言编程规范》 规则1.8 禁止在extern "C"中包含头文件。 #include "clib_hello.h" #include "clib_math.h" } #endif extern "C" void sayHello(void); extern "C" int add(int va ,int vb); //extern void sayHello(void); //extern int add(int va ,int vb);//编译错误,undefined reference to `xxx()' int main() { int i = add(2,3); cout<<"2+3="<<i<<endl; sayHello(); return 0; }
为什么标准头文件都有类似以下的结构?
#ifdef __cplusplus extern "C" { #endif //....头文件主体部分 void cfree(); int malloc_trim(); //.... #ifdef __cplusplus }; /* end of extern "C" */ #endif
这样的结构保证了该头文件可以被cpp或者c程序使用,
如果#ifdef __cplusplus, 头文件主体成为extern "C"{......},保证可被cpp使用。
如果#ifndef __cplusplus, 头文件主体为 ...... ,保证可被c使用。
也有这样的方法:
#ifdef __cplusplus #define CPP_ASMLINKAGE extern "C" #else #define CPP_ASMLINKAGE #endif #define asmlinkage CPP_ASMLINKAGE .... asmlinkage void resume(void); asmlinkage void free(void); ....
2.假如希望c++中定义的函数能被c引用,则加上extern "C";
//cpplib_math.cpp extern "C" int add(int a ,int b) { return a+b; } //cMain.c #include <stdio.h> extern int add(int a,int b); //extern "C" int add(int a,int b);//c中不能有这样的表达式 int main() { int i = add(2,3) ; printf("2+3 = %d\n", i); return 0 ; }
root@ubuntu:~/Desktop/ work/demo/cpplib# g++ -c cpplib_math.cpp root@ubuntu:~/Desktop/ work/demo/cpplib# ar -r libcpplib_math.a cpplib_math.o ar: creating libcpplib_math.a /* root@ubuntu:~/Desktop/ work/demo/cpplib# gcc cMain.c -o cExe -L. -lcpplib_math ./libcpplib_math.a(cpplib_math.o):(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' 用 gcc 连接 C++ 程序也可以,但是需要人为指定连接 C++ 标准库.[4] */ root@ubuntu:~/Desktop/ work/demo/cpplib# gcc cMain.c -o cExe -L. -lcpplib_math -lstdc++ root@ubuntu:~/Desktop/ work/demo/cpplib# l cExe* cMain.c cpplib_math.cpp cpplib_math.o libcpplib_math.a root@ubuntu:~/Desktop/ work/demo/cpplib# ./cExe 2+3 = 5
参考:
1. gcc生成静态库和动态库 http://blog.chinaunix.net/uid-17267213-id-3057974.html
gcc创建和使用静态库、动态库 http://www.cnblogs.com/dyllove98/archive/2013/06/25/3155599.html
2. extern "C"的用法解析 http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html
3.C中如何调用C++函数 http://www.cppblog.com/franksunny/archive/2007/11/29/37510.html
4. 错误:undefined reference to `__gxx_personality_v0' http://blog.csdn.net/dycwahaha/article/details/2636382