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 + 命令 |