1、GCC、gcc、g++的区别:
(1)三者比较
GCC : GNU Compiler Collection(GUN 编译器集合),它可以编译C、C++、JAV、Fortran、Pascal、Object-C、Ada等语言。
gcc是GCC中的GUN C Compiler(C 编译器)
g++是GCC中的GUN C++ Compiler(C++编译器)
一个有趣的事实就是,就本质而言,gcc和g++并不是编译器,也不是编译器的集合,它们只是一种驱动器,根据参数中要编译的文件的类型,调用对应的GUN编译器而已,比如,用gcc编译一个c文件的话,会有以下几个步骤:
Step1:调用预处理器
Step2:调用编译器
Step3:调用汇编器
Step4:调用连接
由于编译器是可以更换的,所以gcc不仅仅可以编译C文件,更准确的说法是:gcc调用了C编译器,而g++调用了C++编译器。
(2)gcc和g++的主要区别
1)对于 *.c和*.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的);
2) 对于 *.c和*.cpp文件,g++则统一当做cpp文件编译;
3)使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL;
4)gcc在编译C文件时,可使用的预定义宏是比较少的;
5)gcc在编译cpp文件时或者g++在编译c文件和cpp文件时(这时候gcc和g++调用的都是cpp文件的编译器),会加入一些额外的宏,这些宏如下:
#define __GXX_WEAK__ 1
#define __cplusplus 1
#define __DEPRECATED 1
#define __GNUG__ 4
#define __EXCEPTIONS 1
#define __private_extern__ extern
6)在用gcc编译c++文件时,为了能够使用STL,需要加参数 –lstdc++ ,但这并不代表 gcc –lstdc++ 和 g++等价,它们的区别不仅仅是这个,主要参数:
-g - turn on debugging (so GDB gives morefriendly output)
-Wall - turns on most warnings
-O or -O2 - turn on optimizations
-o - name of the output file
-c - output an object file (.o)
-I - specify an includedirectory
-L - specify a libdirectory
-l - link with librarylib.a
2、Linux(这里为Ubuntu系统)中安装gcc和g++
1)先安装gcc: sudo apt-get install build-essential
2)查看gcc版本: gcc --version
3)然后安装统一版本的g++: sudo apt-get install g++-x.x
4)查看g++版本:g++ --version
5)查看gcc默认的include路径:`gcc -print-prog-name=cc1plus` -v
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
6)查看g++默认的include路径:`g++ -print-prog-name=cc1plus` -v
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
7)查看gcc默认lib路径:gcc --print-searrch-dir
8)查看g++默认lib路径:g++ --print-search-dir
3、头文件和库文件默认搜索路径
(1)头文件搜索路径:
- 先搜索 -I 指定的目录(这里的 -I 是大写的 i);
- 然后寻找环境变量指定目录:C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH可以通过设置这些环境变量来添加系统include的路径:
export C_INCLUDE_PATH=XXXX:$C_INCLUDE_PATH # C
export CPLUS_INCLUDE_PATH=XXX:$CPLUS_INCLUDE_PATH # CPP
以上修改可以直接命令输入(一次性),可以在/etc/profile中完成(对所有用户生效),也可以在用户home目录下.bashrc或者.bash_profile中添加(针对某个用户生效)。
- 最后搜索gcc的内定目录。
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
(2)库文件搜索路径
编译时:
- gcc会去找-L;
- 再找gcc的环境变量LIBRARY_PATH:LIBRARY_PATH和LD_LIBRARY_PATH是Linux下的两个环境变量,LIBRARY_PATH环境变量用于在程序编译期间查找动态链接库时指定查找共享库的路径,而LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径;
- 再找内定目录:/lib : /usr/lib : /usr/local/lib,这是当初compile gcc时写在程序内的。
运行时:
Linux动态库的默认搜索路径时 /lib 和 /usr/lib,动态库别创建后,都复制到这两个目录中。在Linux中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定:
- 方法一:在配置文件/etc/ld.so.conf中指定动态库搜索路径。但是每次编辑完该文件后,都必须运行命令ldconfig以达到刷新 /etc/ld.so.cache的效果,使修改后的配置生效;
- 方法二:通过环境变量LD_LIBRARY_PATH指定动态库搜索路径;
- 方法三:在编译目标代码时指定该程序的动态库搜索路径。
export LD_LIBRARY_PATH=XXX:$LD_LIBRARY_PATH # 动态链接库搜索路径
export LIBRARY_PATH=XXX:$LIBRARY_PATH # 静态链接库搜索路径
以上修改可以直接命令输入(一次性),可以在/etc/profile中完成(对所有用户生效),也可以在用户home目录下.bashrc或者.bash_profile中添加(针对某个用户生效)。
4、gcc所遵循的部分约定规则:
.c为后缀的文件,C语言源代码文件;
.a为后缀的文件,是由目标文件构成的档案库文件;
.C或.cc或.cxx为后缀的文件,是C++源代码文件;
.h为后缀的文件,是程序所包含的头文件;
.i为后缀的文件,是已经预处理过的C源代码文件;
.ii为后缀的文件,是已经预处理过的C++源代码文件;
.m为后缀的文件,是Objective-C源代码文件;
.o为后缀的文件,是编译后的目标文件,相当于window中.obj文件;
.s为后缀的文件,是汇编语言源代码文件;
.S为后缀的文件,是经过预编译的汇编语言源代码文件。
5、gcc/g++常用的编译命令:
单个文件编译,假设源程序文件名为test.c:
1)无选项编译链接
用法:# gcc test.c
作用:将test.c预处理、汇编、编译并链接形成可执行文件。这里未指定输出文件,默认输出为a.out。
2)选项 -o
用法:# gcc test.c -o test
作用:将test.c预处理、汇编、编译并链接形成可执行文件test。-o选项用来指定输出文件的文件名。
3)选项 -E
用法:# gcc -E test.c -o test.i
作用:将test.c预处理输出test.i文件。
4)选项 -S
用法:# gcc -S test.i
作用:将预处理输出文件test.i汇编成test.s文件。
5)选项 -s
作用:把符号表从最终的可执行文件中删除,这样就不能使用gdb进行调试了
6)选项 -c
用法:# gcc -c test.s
作用:将汇编输出文件test.s编译输出test.o文件。
7)无选项链接
用法:# gcc test.o -o test
作用:将编译输出文件test.o链接成最终可执行文件test。
8)选项-O
用法:# gcc -O1 test.c -o test
作用:使用编译优化级别1编译程序。级别为1~3,级别越大优化效果越好,但编译时间越长。
9)选项-g
用法:# gcc -g test.c -o test
作用:在编译时产生调试信息
10)选项-w
用法:# gcc -w test.c -o test
作用:关闭编译时的警告,不显示任何warming信息
11)选项-Wall
用法:# gcc -Wall test.c -o test
作用:编译时显示所有警告
12)-l(小写L) 需要链接的库名称。即链接库文件去掉lib前缀和.so后的部分。如libev.so就是 -lev
;libace.so就是 -lace
,如果库文件放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find-lxxx”,也就是链接程序ld在那3个目录里找不到。
13)-L 这时另外一个参数-L就派上用场了,比如常用的X11的库,它放在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。
14)-I(大写i) include头文件的搜索路径。当有此选项时,优先搜索此路径下的头文件。然后按照#include后面是""还是<>来决定是优先在当前目录搜索还是优先在系统目录搜索。默认头文件的路径为当前目录./
和系统目录 /usr/include
/usr/local/include
。
15)-Werror 视警告为错误,出现任何警告就放弃编译。
16)-fPIC 和 -fpic等价: 作用于编译阶段,告诉编译器产生与位置无关的代码,则产生的代码中没有绝对地址,只有相对地址。因此代码可以被加载到内存的任意位置,这正是共享库.so所需要的。所有的固定地址的访问都是通过全局偏移表来实现的, -fPIC对全局偏移表(GOT)的大小无限制,-fpic对GOT表的大小有限制。
17)-fPIE 和 -fpie等价: 作用于编译阶段,编译出来的.o文件时与位置无关的。
18)-pie: 作用于链接阶段,从.o文件链接出来的可执行文件是与位置无关的。
如果有多个源文件,基本上有两种编译方法,假设有两个源文件为test.c和testfun.c:
1)多个文件一起编译
用法:# gcc testfun.c test.c -o test
作用:将testfun.c和test.c分别编译后链接成test可执行文件。
2)分别编译各个源文件,之后对编译后输出的目标文件链接。
用法:
# gcc -c testfun.c //将testfun.c编译成testfun.o
# gcc -c test.c //将test.c编译成test.o
# gcc -o testfun.o test.o -o test //将testfun.o和test.o链接成test