学一下gcc和gdb,巩固基础.
gcc与gdb都是GNU软件,是GNU组织,这个组织是由一个黑客大佬公开发起创建对抗商业软件,并开发操作系统的.
GCC是C语言编译器,现在在windows上有MinGW.
开始
GCC
在使用 GCC 编译程序时,编译过程可以被细分为四个阶段:
- 预处理(Pre-Processing)
- 编译(Compiling)
- 汇编(Assembing)
- 链接(Linking)
在windows上装的gcc.
可以看到是mingw
Linux上一般是
命令
1 | gcc xx.c |
将c源文件经过处理得到可执行文件a.out,名字是默认的1
gcc xx.c -o demo.out
-o指定输出文件名
这样就能直接得到可执行文件
下面简单介绍四个过程的命令1
2
3
4gcc -E //预处理
gcc -S //编译
gcc -c //汇编
gcc -o //链接
另外还有一些比较有用的命令1
2
3
4
5
6gcc -o xx xx.o xx.o .. -static //静态链接
gcc -Wall ... //生成所有警告信息
gcc -O0
gcc -O1
gcc -O2 ...//优化代码
gcc -g //生成调试信息,方便debug
警告与优化
除了上述四个过程,gcc还有代码警告和优化.1
2-pedantic
-Wall
主要这两个命令,其实一般用-Wall就行了,这样能产生更多的警告信息.
pedantic是尽量让代码符合ANSI/ISO标准.
优化命令1
2
3
4-O0
-O1
-O2
-O3
值越大,优化等级越高.
经过测试发现貌似文件大小一样.
但是运行时间不一样,可以用time来计算
- 程序开发的时候:优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。
- 资源受限的时候:一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。
- 跟踪调试的时候:在对代码进行优化的时候,某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难
选项名 | 作用 |
---|---|
-c | 通知 GCC 取消连接步骤,即编译源码并在最后生成目标文件。 |
-Dmacro | 定义指定的宏,使它能够通过源码中的 #ifdef 进行检验。 |
-E | 不经过编译预处理程序的输出而输送至标准输出。 |
-g3 | 获得有关调试程序的详细信息,它不能与 -o 选项联合使用。 |
-Idirectory | 在包含文件搜索路径的起点处添加指定目录。 |
-llibrary | 提示连接程序在创建最终可执行文件时包含指定的库。 |
-O -O2 -O3 | 将优化状态打开,该选项不能与 -g 选项联合使用。当出现多个优化时,以最后一个为准。 |
-O0 | 关闭所有优化选项。 |
-S | 要求编译程序生成来自源代码的汇编程序输出。 |
-v | 启动所有警报。 |
.h | 预处理文件(标头文件)。 |
-Wall | 在发生警报时取消编译操作,即将警报看作是错误。 |
-w | 禁止所有的报警。 |
-share | 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库。 |
-shared | 产生共享对象文件。 |
-g | 在编译结果中加入调试信息。 |
-ggdb | 加入 GDB 调试器能识别的格式。 |
这里就不详细说了,后面会对编译进一步说明.
后面介绍gdb
GDB
一般来说,GDB 主要帮忙你完成下面几个方面的功能:
- 设置断点(断点可以是条件表达式),使程序在指定的代码行上暂停执行,便于观察。
- 单步执行程序,便于调试。
- 查看程序中变量值得变化。
- 动态改变程序的执行环境。
- 分析崩溃程序产生的 core 文件
为了使 GDB 正常工作,必须使程序在编译的时候包含调试信息,这需要在 GCC 编译时加上 -g
或者 -ggdb
选项。调试信息包好了程序中的每个变量的类型和在可执行文件中的地址映射以及源代码的行号。而 GDB 正是利用这些信息是源代码和机器码相关联。
命令 | 含义描述 |
---|---|
file | 装入想要的调试的可执行文件。 |
run | 执行当前被调试的程序。 |
kill | 终止正在调试的程序。 |
step | 执行一行源代码而且进入函数内部。 |
next | 执行一行源代码但不进入函数内部。 |
break | 在代码里设置断点,这将使程序执行到这里时被挂起。 |
打印表达式或变量的值,或打印内存中某个变量开始的一段连续区域的值,还以用来对变量进行赋值。 | |
display | 设置自动显示的表达式或变量,当程序停住或在单步追踪时,这些变量会自动显示其当前值。 |
list | 列出产生执行文件的源代码的一部分。 |
quit | 退出 GDB。 |
watch | 使你能监视一个变量的值而不管它何时被改变。 |
backtrace(或 bt) | 回溯追踪。 |
frame n | 定位到发生错误的代码段,n 为 backtrace 命令的输出结果中的行号。 |
examine | 查看内存地址中的值。 |
jump | 是程序跳转执行。 |
signal | 产生信号量。 |
return | 强制函数返回。 |
call | 强制调用函数。 |
make | 使用户不退出 GDB 就可以重新产生可执行文件。 |
shell | 使用户不离开 GDB 就执行 Linux 的 shell 命令。 |
常用命令
list查看源代码1
2
3
4list 20 //查看第20行代码前后10行代码
list main //查看main函数左右10行代码
list //往后查看10行代码
list - //往前查看10行代码
run运行,遇到断点停
file 将一个可执行文件装入
break 简写b 打断点 可以在行号和函数名处打断点,当然,这个命令功能很强.还可以在内存地址打断点.
info break简写i b,查看断点信息
delete num 删除断点 disable num 禁用断点
info 命令可以在调试时用来查看寄存器、断点、观察点和信号等信息
gdb调试
当代码出现错误时,首先通过backtrace(bt)进行错误定位可以得到出错的行
然后使用frame命令定位到出错代码
程序被停住后,可以使用 continue
命令(缩写 c
)恢复程序的运行直到程序结束,或到达下一个断点
使用watch命令查看变量值的变化.
- 使用
break
命令在要观察的变量所在处设置断点。 - 使用
run
命令执行,直到断点。 - 使用
watch
命令设置观察点。 - 使用
continue
命令观察设置的观察点是否有变化
print命令输出变量值,
x
:按十六进制格式显示变量。d
:按十进制格式显示变量。u
:按十六进制格式显示无符号整型。o
:按八进制格式显示变量。t
:按二进制格式显示变量。a
:按十六进制格式显示变量。c
:按字符格式显示变量。f
:按浮点数格式显示变量
print a[4]
:打印a[4]
的值。print a+4
:打印a[4]
的地址。print &a[4]
:打印a[4]
的地址。x a[4]
:访问a[4]
值所代表的内存,即打印a[4]
值代表内存里面的值。x a+4
:访问指针a+4
代表内存里面的值,即 5。x &a[4]
:访问指针a+4
代表内存里面的值,即 5。x &(a+4)
:访问a+4
指针所在的地址,不存在。
print
就是打印给定变量(参数是什么,就打印什么),x
打印给定变量代表的内存地址里的值(即 x
后面的参数 是地址值,打印的是地址所在内存单元的值
help命令帮助