Linux应用编程基础学习笔记
GCC程序编译
Linux系统下的gcc (GNU C Compiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作之一。GCC编译器能将c、c++语言源程序、汇编程序编译、链接成可执行文件。在Linux系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件
GCC编译程序时,分为四个阶段:
- 预处理(Pre-Processing)
- 编译(Comiling)
- 汇编(Assembling)
- 链接(Linking)
GCC通过文件后缀来区分输入文件的类型:
.c:c语言源代码文件
.a:目标文件构成的库文件
.cc、.cXX:C++源代码文件
.i:已经预处理过得c源代码文件
.ii:已经预处理过得c++源代码文件
.o:编译后的目标文件
.s:汇编语言源代码文件
.S:经过预编译的汇编语言源代码文件
gcc最基本的用法如下:
gcc [options] [filenames]
options: 编译器所需要的编译选项(100多个选项)
filenames: 要编译的文件名
编译选项 | 说明 | 举例 |
---|---|---|
aaaaaaaaaaaaaaa | 调整makrdown表格宽度 | |
-o output_filename | 确定可执行文件的名称为output_filename,如果不写名称,默认生成可执行文件a.out | |
-c | 只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件 | |
-g | 产生调试工具(GNU的gdb)所必要的符号信息,要想用gdb调试,必须加入这个选项 | |
-O | 对程序进行优化编译、链接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样的可执行文件的执行效率可以提高,但是,编译、连接的速度会慢一些 | |
-O2 | 更好的优化编译、链接 | gcc optimize.c -o optimize root@ubuntu:time ./optimize gcc -O optimize.c -o optimize root@ubuntu:time ./optimize |
-ldirname | 将dirname所指出的目录加入到程序头文件目录列表中 | gcc foo.c -l /home/include -o foo |
-Ldirname | 将dirname所指出的目录加入到库文件的目录列表中。默认状态,连接程序ld在系统的预设定路径中(如/usr/lib)寻找所需要的库文件,这个选项告诉连接程序,首先到-L指定的目录中去寻找,然后再去指定的路径寻找 | |
-lname | 在连接时,装载名字为“libname.a”的函数库。例如,-lm表示连接名为“libm.a”的数学函数库 | gcc foo.c -L /home/lib -lfoo -o foo |
-static | 静态链接库文件(把库文件在源代码应用的地方展开,拷贝过去,相对动态链接,在代码执行时才去调用库函数来说,浪费空间)Linux下进行的连接默认为动态库 | gcc -static hello.c -o hello |
-Wall | 生成所有告警信息 | |
-w | 不生成任何警告信息 | |
-DMACRO | 定义MACRO宏,等效于#define MACRO | gcc -DMACRO hello.c -o hello |
-E | 查看宏展开后的内容 | g++ -E .cpp/.h > *.txt |
比如代码中:
#ifdef MACRO /定义了,则下面的程序会被执行/
…
#endif |
GDB 调试
GDB是GNU发布的一款功能强大的程序调试工具。GDB主要完成下面三个方面的功能:
- 启动被调试程序
- 让被调试的程序在指定的位置停住
- 当程序被停住时,可以检查程序状态
步骤如下:
A. 编译生成可执行文件:
gcc -g test.c -o test
B. 启动GDB
gdb test
C. 在函数处设断点
break main
D. 运行程序
run
E. 单步执行
next
GDB常用命令简介:
常用命令 | 缩写 | 命令说明 |
---|---|---|
aaaaaaaaaaaaaaaaaa | aaaa | 调整makrdown表格宽度 |
list | l | 查看程序 |
break 函数名 | b | 在函数入口处添加断点 |
break 行号 | b | 在指定行添加断点 |
break 文件名:行号 | b | 在指定文件的指定行添加断点 |
break 行号 if 条件 | b | 当条件为真时,指定行号出断点生效,例b 5 if i=10,当i等于10时第5行断点生效 |
info break | 查看所有设置的断点 | |
delete 断点编号 | d | 删除断点 |
run | r | 开始运行程序 |
next | n | 单步运行程序(不进入子函数) |
step | s | 单步运行(进入子函数) |
continue | c | 继续运行程序 |
print 变量名 | p | 查看指定的变量值 ,打印指定寄存器print $rsp |
watch 变量名 | 对指定变量进行监控 | |
quit | q | 退出gdb |
backtrace | bt | 产看函数调用信息(堆栈) |
disas | 检查汇编 会给出对应的代码的汇编 | |
info registers | 查看寄存器内容 | |
x | 检查寄存器或某个地址 x/4wd $rsp、x $esi | |
attach 进程id | 调试某个进程id,例如。假如用ps查看进程qs进程的id为987,用gdb调试这个进程中的函数./gdb attach 987,进入进程后先打断点b,在运行程序c,如果程序执行到断点处,则可以停在断点处,bt查看调用栈 | |
如何用gdb单独调用某个函数 | 假如调用struct l2if * l2if_get(uint32_t ifindex)函数,这个函数在l2进程,先用ps查看l2进程的进程id,然后t调用gdb(./gdb attach 进程id)(gdb) set $pif = l2if_get(0x22105000) (gdb) p /x *$pif | |
(gdb)p/x p0->data[0]@64 | 查看p0指向的data存储的64个字节 |
如何格式化输出数据结构?
set print array on
set print array off
show print array
以可读形式打印数组。默认是 off 。
set print array-indexes on
set print array-indexes off
show print array-indexes
打印数组元素的下标。默认是 off 。
set print pretty on
set print pretty off
show print pretty
格式化打印 C 结构体的输出
详细gdb格式参见geb格式输出
gdb调试举例:
(gdb) set $pif = l2if_get(0x22105000)
(gdb) p /x *$pif
/*调用相关函数 */
call test_l2_mac_add(0x01, 0x00, 0x0c, 0xcd, 0xcd, 0xd2,200,0)
set $trunk_infor = (bcm_trunk_chip_info_t*)malloc(sizeof(bcm_trunk_chip_info_t))
call bcm_trunk_chip_info_get(0, $trunk_infor)
更多用法请查看此篇文章gdb教程
makefile工程管理
Linux程序员必须学习使用GNU make来构建和管理自己的软件工程。GNU的make命令能够使整个软件工程的编译、链接只需一个命令就可以完成。make在执行时,需要一个命名为Makefile的文件(不区分大小写)。Makefile文件描述了整个工程的编译,链接等规则。例:
hello:main.o func1.o
gcc main.o func1.o -o hello
main.o:main.c
gcc -c main.c
func1.o:func1.c
gcc -c func1.c
.PHONY:clean
clean:
rm -f hello main.o func1.o
上面的写法可以进一步优化:
hello:main.o func1.o
gcc $^ -o $@
%.o:%.c
gcc -o $@ -c $<
clean:
rm -f hello *.o
规则:用于说明如何生成一个或多个目标文件,格式如下:
targets:prerequisites
(一个tab键位)command
目标 依赖 命令
通过这个规则可以看出,上面的例子有3条规则,并且在Makefile中目标可能有很多,但是第一条规则中的目标将被确立为最终的目标,也就是hello。
问:命令什么时候被执行?
答:1. 目标不存在时(hello程序不存在); 2. 依赖更新时(.c文件更新后)
- Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phony targets),如上面的clean,敲命令make clean即会执行clean:中的命令
- Makefile中可以使用变量,例如:
obj = main.o func1.o
hello:$(obj)
gcc $(obj) -o hello - 在Makefile中存在一些系统默认的自动化变量
- $^:代表所有的依赖文件
- $@:代表目标
- $<:代表第一个依赖文件
例如:
hello:main.o func1.o
gcc main.o func1.o -o hello
=》
hello:main.o func1.o
gcc $^ -o $@
- Makefile中“#”字符后的内容被视为注释
- 取消回显加@,例如
hello:helloc.c
@gcc hello.c -o hello