gcc和g++的区别以及extern \"C\"的作用

痴心易碎 提交于 2020-01-11 09:13:29

首先来写一个简单的c代码~

1 //externC_funA.c2 void funA()3 {}

利用gcc进行编译生成汇编:

gcc -c externC_funA.c -S

得到的汇编代码如下:

 1 .file    "externC_funA.c" 2     .text 3 .globl funA   //注意这里的标示符为funA 4     .type    funA, @function 5 funA: 6     pushl    %ebp 7     movl    %esp, %ebp 8     popl    %ebp 9     ret10     .size    funA, .-funA11     .ident    "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"12     .section    .note.GNU-stack,"",@progbits

同样的,我们将该文件改为cpp后缀,重新编译

1 //externC_funA.cpp2 void funA()3 {}
gcc -c externC_funA.cpp -S
g++ -c externC_funA.cpp -S

按照上面两种方法编译,得到的汇编代码一样

 1 .file    "externC_funA.cpp" 2     .text 3 .globl _Z4funAv//注意这里的标示符为_Z4funAv,不同形参版本的funA生成的标示符会不一样! 4     .type    _Z4funAv, @function 5 _Z4funAv: 6 .LFB2: 7     pushl    %ebp 8 .LCFI0: 9     movl    %esp, %ebp10 .LCFI1:11     popl    %ebp12     ret13 .LFE2:14     .size    _Z4funAv, .-_Z4funAv15     .ident    "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"16     .section    .note.GNU-stack,"",@progbits

第三个例子:

//externC_funA.cpp
1 void funA()2 {}3 void funA(int a)4 {}

得到的汇编如下:

 1     .file    "externC_funA.cpp" 2     .text 3 .globl _Z4funAv//funA()对应的标示符,最后那个v表示void形参 4     .type    _Z4funAv, @function 5 _Z4funAv: 6 .LFB2: 7     pushl    %ebp 8 .LCFI0: 9     movl    %esp, %ebp10 .LCFI1:11     popl    %ebp12     ret13 .LFE2:14     .size    _Z4funAv, .-_Z4funAv15 .globl _Z4funAi//funA(int)对应的标示符,最后那个i表示int形参16     .type    _Z4funAi, @function17 _Z4funAi:18 .LFB3:19     pushl    %ebp20 .LCFI2:21     movl    %esp, %ebp22 .LCFI3:23     popl    %ebp24     ret25 .LFE3:26     .size    _Z4funAi, .-_Z4funAi27     .ident    "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"28     .section    .note.GNU-stack,"",@progbits

从上面的两个对比,我们可以得到下面几个结论:

1.gcc会自动识别文件的后缀名,对于.c文件,gcc按照c语言的方式进行编译;而对于.cxx文件,gcc按照c++语言的方式进行编译。

2.c++能够实现重载的原因是,编译器对不同形参版本的函数,生成的标示符会不同。

3.对于cxx文件,在编译阶段,g++和gcc是等价的。

那么g++跟gcc又有什么区别呢,主要的区别是在链接阶段。

//externC_funA.cppvoid funA(){}//externC.cppextern void funA();int main(){    funA(); //按照此种方法,生成的汇编为    call    _Z4funAv
gcc -c externC_funA.cpp      //    .globl _Z4funAvgcc -c externC.cpp           //    call   _Z4funAvgcc -o externC externC.o externC_funA.o //undefined reference to `__gxx_personality_v0'

按道理生成的标示符是_Z4funAv,调用的也是_Z4funAv,应该没错啊,为什么在链接的时候出错了呢?主要是最后一步用的是gcc来进行链接,而显然gcc不支持c++方式的链接,所以会报错。如果改成以下就不会出现问题了。

g++ -o externC externC.o externC_funA.o

继续试验!!!

将externC_funA.cpp改成externC_funA.c

//externC_funA.cvoid funA(){}//externC.cppextern void funA();int main(){    funA();}
gcc -c externC_funA.c               //.globl funAgcc -c externC.cpp.globl funA       //call_Z4funAvg++ -o externC externC.o externC_funA.o //undefined reference to `funA()'

出现上面这个错误是明显的,因为两个标示符根本就不一样,就算用了g++也是不起作用的~~所以此时extern "C"就可以发挥作用了。

//externC_funA.cvoid funA(){}//externC.cppextern "C"{extern void funA();}int main(){    funA();//通过加入extern “C”,此处生成的汇编为  call    funA}
gcc -c externC_funA.c     gcc -c externC.cppg++ -o externC externC.o externC_funA.o


到这里,也不用我来总结了,extern “C”的作用一目了然~按照c语言的方式生成汇编,以免造成链接错误。extern "C"主要的应用就在于一个c的链接库已经生成好,不想再修改了,或者说这个链接库是别人写的,不知道源代码,根本就没法修改。在这种情况下,我们用C++调用库中的函数就能够正确链接了。







标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!