典当行网站模板,wordpress改企业网站,小程序sdk开发,偃师网站建设一#xff1a;gcc与g比较 编译c/c代码的时候#xff0c;有人用gcc#xff0c;有人用g#xff0c;于是各种说法都来了#xff0c;譬如c代码用gcc#xff0c;而 c代码用g#xff0c;或者说编译用gcc#xff0c;链接用g#xff0c;一时也不知哪个说法正确#xff0c;如果… 一gcc与g比较 编译c/c代码的时候有人用gcc有人用g于是各种说法都来了譬如c代码用gcc而 c代码用g或者说编译用gcc链接用g一时也不知哪个说法正确如果再遇上个extern C分歧就更多了这里我想作个了结毕竟知识的目的是令人更清醒而不是更糊涂。 误区一:gcc只能编译c代码,g只能编译c代码 两者都可以但是请注意 1.后缀为.c的gcc把它当作是C程序而g当作是c程序后缀为.cpp的两者都会认为是c程序注意虽然c是c的超集但是两者对语法的要求是有区别的例如 #include int main(int argc, char* argv[]) { if(argv 0) return; printString(argv); return; } int printString(char* string) { sprintf(string, This is a test.\n); } 如果按照C的语法规则OK没问题但是一旦把后缀改为cpp立刻报三个错“printString未定义” “cannot convert char** to char*” ”return-statement with no value“ 分别对应前面红色标注的部分。可见C的语法规则更加严谨一些。 2.编译阶段g会调用gcc对于c代码两者是等价的但是因为gcc命令不能自动和C程序使用的库联接所以通常用g来完成链接为了统一起见干脆编译/链接统统用g了这就给人一种错觉好像cpp程序只能用g似的。 误区二:gcc不会定义__cplusplus宏而g会 实际上这个宏只是标志着编译器将会把代码按C还是C语法来解释如上所述如果后缀为.c并且采用gcc编译器则该宏就是未定义的否则就是已定义。 误区三:编译只能用gcc链接只能用g 严格来说这句话不算错误但是它混淆了概念应该这样说编译可以用gcc/g而链接可以用g或者gcc -lstdc。因为gcc命令不能自动和C程序使用的库联接所以通常使用g来完成联接。但在编译阶段g会自动调用gcc二者等价。 误区四:extern C与gcc/g有关系 实际上并无关系无论是gcc还是g用extern c时都是以C的命名方式来为symbol命名否则都以c方式命名。试验如下 me.h extern C void CppPrintf(void); me.cpp: #include #include me.h using namespace std; void CppPrintf(void) { cout Hello\n; } test.cpp: #include #include #include me.h int main(void) { CppPrintf(); return 0; } 1. 先给me.h加上extern C看用gcc和g命名有什么不同 [rootroot G]# g -S me.cpp [rootroot G]# less me.s .globl _Z9CppPrintfv //注意此函数的命名 .type CppPrintf, function [rootroot GCC]# gcc -S me.cpp [rootroot GCC]# less me.s .globl _Z9CppPrintfv //注意此函数的命名 .type CppPrintf, function 完全相同 2. 去掉me.h中extern C看用gcc和g命名有什么不同 [rootroot GCC]# gcc -S me.cpp [rootroot GCC]# less me.s .globl _Z9CppPrintfv //注意此函数的命名 .type _Z9CppPrintfv, function [rootroot G]# g -S me.cpp [rootroot G]# less me.s .globl _Z9CppPrintfv //注意此函数的命名 .type _Z9CppPrintfv, function 完全相同 【结论】完全相同可见extern C与采用gcc/g并无关系以上的试验还间接的印证了前面的说法在编译阶段g是调用gcc的。 二gcc和的包含头文件库文件方法 -l参数就是用来指定程序要链接的库-l参数紧接着就是库名那么库名跟真正的库文件名有什么关系呢就拿数学库来说他的库名是m他的库文件名是libm.so很容易看出把库文件名的头lib和尾.so去掉就是库名了。 好了现在我们知道怎么得到库名当我们自已要用到一个第三方提供的库名字libtest.so那么我们只要把 libtest.so拷贝到/usr/lib里编译时加上-ltest参数我们就能用上libtest.so库了当然要用libtest.so库里 的函数我们还需要与libtest.so配套的头文件 放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了但如果库文件没放 在这三个目录里而是放在其他目录里这时我们只用-l参数的话链接还是会出错出错信息大概是“/usr/bin/ld: cannot find -lxxx”也就是链接程序ld在那3个目录里找不到libxxx.so这时另外一个参数-L就派上用场了比如常用的X11的库它在/usr /X11R6/lib目录下我们编译时就要用-L/usr/X11R6/lib -lX11参数-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下那链接参数就是-L /aaa/bbb/ccc -ltest 另外大部分libxxxx.so只是一个链接以RH9为例比如libm.so它链接到/lib/libm.so.x/lib/libm.so.6又链接到/lib/libm-2.3.2.so 如果没有这样的链接还是会出错因为ld只会找libxxxx.so所以如果你要用到xxxx库而只有libxxxx.so.x或者libxxxx-x.x.x.so做一个链接就可以了ln -s libxxxx-x.x.x.so libxxxx.so 手工来写链接参数总是很麻烦的还好很多库开发包提供了生成链接参数的程序名字一般叫xxxx-config一般放在/usr/bin目录下比如 gtk1.2的链接参数生成程序是gtk-config执行gtk-config --libs就能得到以下输出-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm这就是编译一个gtk1.2程序所需的gtk链接参数xxx-config除了--libs参数外还有一个参数是--cflags用来生成头 文件包含目录的也就是-I参数在下面我们将会讲到。你可以试试执行gtk-config --libs --cflags看看输出结果 现在的问题就是怎样用这些输出结果了最笨的方法就是复制粘贴或者照抄聪明的办法是在编译命令行里加入这个 xxxx-config --libs --cflags比如编译一个gtk程序gcc gtktest.c gtk-config --libs --cflags这样就差不多了。注意不是单引号而是1键左边那个键。 5、-include和-I参数 -include用来包含头文件但一般情况下包含头文件都在源码里用#include xxxxxx实现-include参数很少用。-I参数是用来指定头文件目录/usr/include目录一般是不用指定的gcc知道去那里找但 是如果头文件不在/usr/include里我们就要用-I参数指定了比如头文件放在/myinclude目录里那编译命令行就要加上-I /myinclude参数了如果不加你会得到一个xxxx.h: No such file or directory的错误。-I参数可以用相对路径比如头文件在当前目录可以用-I.来指定。 结论例子 g curltest.cpp -o curltest -L/mnt/hgfs/windows/curl-7.19.5/lib/.libs -lcurl -I/mnt/hgfs/windows/curl-7.19.5/include