GCC编译器和GDB调试器
GCC编译器
GCC 编译器支持编译 Go、Objective-C,Objective-C++,Fortran,Ada,D 和 BRIG(HSAIL)等程序。
实际使用中,使用 gcc 指令编译 C 代码,使用 g++ 指令编译 C++ 代码。
编译过程
例如 g++ test.cpp -o test 可拆解为以下步骤:
- 预处理:处理以 # 开头的预处理命令 - 1 
 2
 3
 g++ -E test.cpp -o test.i // 生成.i文件
- 编译:翻译成汇编文件 - 1 
 2
 3
 4
 g++ -S test.i -o test.s
- 汇编:将汇编文件翻译成可重定位目标文件 - 1 
 2
 3
 4
 g++ -c test.s -o test.o
- 链接:将可重定位目标文件和 printf.o 等单独预编译好的目标文件进行合并,得到最终的可执行目标文件 - 1 
 2
 3- # -o 编译选项来为将产生的可执行文件用指定的文件名 
 # test 为可执行文件
 g++ test.o -o test- 静态链接和动态链接- 动态库一般都会存在/usr/lib/ 目录下;而静态库可以在任何目录下,只要你第一次链接的时候,用绝对路径去链接就行了,之后再删除,是不会影响你的生成的执行文件的。 
当然动态库和静态库可以放置到你想放的任何地方,只是动态库需要设置环境变量,而静态库链接的时候需要绝对路径。
静态连接:
源文件中包含的头文件和程序中使用到的库函数,如stdio.h中定义的printf()函数,在libc.a中找到目标文件printf.o(这里暂且不考虑printf()函数的依赖关系),然后将这个目标文件和我们hello.o这个文件进行链接形成我们的可执行文件。
可以发现静态运行库里面的一个目标文件只包含一个函数,如libc.a里面的printf.o只有printf()函数,strlen.o里面只有strlen()函数。因为如果很多函数都放在一个目标文件中,很可能很多没用的函数都被一起链接进了输出结果中,十分浪费空间。
缺点是浪费空间,因为每一个可执行程序都需要堆关联的静态库目标文件有一份拷贝,因此同一个目标文件可能在内存里就有多次拷贝。一旦代码修改,也得重新进行编译。
优点就是可执行程序已经具备了这些库文件,因此运行时的速度更快。
动态连接:
简单来说就是目标文件不会在链接阶段链接,而是推迟到了运行时,检查相关目标文件是否已经存在于内存之中,即共享一份副本。
也就是生成的可执行文件并没有要链接的内容,代码运行后再去找,这时候如果动态库被删除,就无法成功运行。
优点是空间占用更少,缺点是运行时效率降低,但一般不超过5%,因此可以忽略。
g++重要编译参数
- -g 编译带调试信息的可执行文件 - 1 
 2
 3- # -g 选项告诉 GCC 产生能被 GNU 调试器 GDB 使用的调试信息,以调试程序。 
 # 产生带调试信息的可执行文件 test(不加则 test 不包含调试信息)
 g++ -g test.cpp -o test
- -O[n] 优化源代码 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 g++ -O2 test.cpp
- -l 和 -L 指定库文件 | 指定库文件路径 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 g++ -lglog test.cpp
 g++ -L/home/Test -lmytest test.cpp
- -I 指定头文件搜索目录 - 1 
 2- # 若头文件在 /usr/include 目录下一般是不需要指定的,否则就需要 -I 参数来指定了,比如头文件放在 /myinclude 目录里,否则会报错 “xxxx.h: No such file or directory” 。 
 g++ -I/myinclude test.cpp
- -Wall 打印警告信息 | -w 关闭警告信息 - 1 
 2
 3
 4
 5- # 打印出 gcc 的警告信息 
 g++ -Wall test.cpp
 # 关闭所有警告信息
 g++ -w test.cpp
- -std=c++11 设置编译标准 - 1 
 2- # 使用 c++11 标准编译 test.cpp 
 g++ -std=c++11 test.cpp
- -o 指定输出文件名 1 
 2
 3# 指定即将产生的文件名 
 # 指定输出可执行文件名为test
 g++ test.cpp -o test
- -D 定义宏 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- # 在使用gcc/g++编译的时候定义宏 
 # 常用场景:
 # -DDEBUG 定义 DEBUG 宏,可能文件中有DEBUG宏部分的相关信息,用 DDEBUG 来选择开启或关闭 DEBUG
 # 举例:
 // -Dname 定义宏 name,默认定义内容为字符串 “1”
 int main()
 {
 
 printf("DEBUG LOG\n");
 
 printf("in\n");
 }
 // 1. 在编译的时候,使用g++ -DDEBUG main.cpp
 // 2. 第七行代码可以被执行- GDB调试器
GDB(GNU Debugger) 是一个用来调试C/C++程序的功能强大的调试器,是 Linux 系统开发 C/C++ 最常用的调试器。
GDB主要功能:
- 设置断点(断点可以是条件表达式)
- 使程序在指定的代码行上暂停执行,便于观察
- 单步执行程序,便于调试
- 查看程序中变量值的变化
- 动态改变程序的执行环境
- 分析崩溃程序产生的core文件
调试开始:执行gdb [filename] ,进入gdb调试程序,其中 filename 为要调试的可执行文件名。
编译程序时需要加上 -g,之后才能用 gdb 进行调试:g++ -g main.cpp -o main
回车键:重复上一命令
| 1 | (gdb)help(h) # 查看命令帮助,具体命令查询在gdb中输入help + 命令 |