您的位置:首页 > 运维架构 > Linux

Linux下C开发——gcc,gdb的使用

2009-11-13 11:56 323 查看
Linux



C

开发——

gcc



gdb

的使用


作者:
zccst

我们学习的过程应该是一个积累的过程,有无到有,又少到多,而不能像下山的猴子。
9
月份的时候是第一次系统学习
gcc, gdb, makefile
(详见前面博客)。如今作为嵌入式系统的一个组成部分,决定重学一次,感觉理解加深了一些。

gcc

编译器


前提编辑工具的使用:
vi
vim
Emacs
等。

理论篇


gcc
可以使程序员灵活地控制编译过程。编译过程一般可以分为下面四个阶段,每个阶段分别调用不同的工具进行处理,如图
9-18
所示。

Linux
系统中可执行文件有两种格式。第一种格式是
a.out
格式,这种格式用于早期的
Linux
系统以及
Unix
系统的原始格式。
a.out
来自于
Unix C
编译程序默认的可执行文件名。当使用共享库时,
a.out
格式就会发生问题。把
a.out
格式调整为共享库是一种非常复杂的操作,由于这个原因,一种新的文件格式被引入
Unix
系统
5
的第四版本和
Solaris
系统中。它被称为可执行和连接的格式(
ELF
)。这种格式很容易实现共享库。

ELF
格式已经被
Linux
系统作为标准的格式采用。
gcc
编译程序产生的所有的二进制文件都是
ELF
格式的文件(即使可执行文件的默认名仍然是
a.out
)。较旧的
a.out
格式的程序仍然可以运行在支持
ELF
格式的系统上。

注:
GCC
支持数种调试和剖析选项。在这些选项里,最常用的是
-g

-pg
选项。

实践篇


gcc
的使用格式:
gcc
[options][filenames]

其中
filenames
为所要编译的程序源文件。
options
见下文
gcc
的主要参数。

当使用
gcc
时,
gcc
会完成预处理、编译、汇编和连接。前三步分别生成目标文件,连接时,把生成的目标文件链接成可执行文件。
gcc
可以针对支持不同的源程序文件进行不同处理,文件格式以文件的后缀来识别。

vi hello.c

一、常见步骤:

对于只有一个源文件的简单程序,常常只有编译,运行两步。

1

gcc hello.c -o hello

2

./hello

二、
gcc
编译流程

gcc and g++
分别是
gnu

c & c++
编译器
gcc/g++
在执行编译工作的时候,总共需要
4


hello.c

(
源码
)

1

hello.i

生成预处理文件,

参数是“
-E
”,把
hello.c -> hello.i
。完整命令为
gcc hello.c -o hello.i -E

2

hello.s

编译生成汇编文件,

参数是“
-S
”,把
hello.i -> hello.s
。完整命令为
gcc hello.i -o hello.s -S

3

hello.o

将汇编文件变为目标代码,

参数是“
-c
”,把
hello.s -> hello.o
。完整命令为
gcc hello.s -o hello.o -c

4

hello

链接目标代码,生成可执行程序,

参数无,


hello.o
-> hello


完整命令为
gcc
hello.o -o hello

./hello

(
运行
)

三、
gcc
的主要参数

1
,总体参数

-E

只进行预编译,不做其他处理

-S

只是编译不汇编,生成汇编代码

-c

只是编译不链接,生成目标文件“
.o


-o file

把输出文件输出到
file


-g

在可执行程序中包含标准调试信息

-v

打印出编译器内部编译各过程的命令行信息和编译器的版本

-I dir

在头文件的搜索路径列表中添加
dir
目录

-L dir

在库文件的搜索路径列表中添加
dir
目录

-static

链接静态库

-llibrary

连接名为
library
的库文件

2
,警告和出错参数。

-w

关闭警告

-ansi

显示不符合
ANSI C
标准语法的警告信息

-pedantic

-Wall

跟踪调试的有力工具,最后养成使用此参数的习惯。

3
,查找选项

gcc
一般使用默认路径查找头文件和库文件。如果文件所用的头文件或库文件不在缺省目录下,则编译时要指定它们的查找路径。

-I
选项:指定头文件的搜索目录

例:
gcc –I/export/home/st
–o test1 test1.c

-L
选项:指定库文件的搜索目录

例:
gcc –L/usr/X11/R6/lib
–o test1 test1.c

4
,优化参数。

通过参数“
-On
”来生成优化代码。其中
n
是一个代表优化级别的整数,较典型范围是从
0

2

3.
数字越大优化的等级越高,程序运行速度越快。常用
-O2
,因为它在优化长度,编译时间和代码大学之间取得一个比较理想的平衡点。比较:
1-8.c(
代码略
)

gcc 1-8.c -o 1-8

time ./1-8

gcc 1-8.c -o 1-8 -O2

time ./1-8

注:如下场合应避免优化代码。

(1)
程序开发时。只有到软件发行或开发结束时,才考虑对最终生成的代码进行优化。

(2)
资源受限时。如内存资源非常紧张时(一些实时嵌入式设备)。

(3)
跟踪调试时。优化可能会删除、改写或重组代码,从而使跟踪调试变得异常困难。

gdb

调试器


理论篇


gdb
调试的不是
.c
源文件而是可执行文件,然而,并不是所有的可执行文件都可以用
gdb
调试。如果要让产生的可执行文件可以用来调试,需在执行
gcc
指令编译程序时,加上
-g
参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。
gdb
利用这些信息使源代码和机器码相关联。

实践篇


gdb
使用格式:
gdb filename

其中,
filename
是要调试的可执行文件。用这种方式运行
gdb
可以直接指定想要调试的程序。这和启动
gdb
后执行
file filename

file
命令:装入想要调试的可执行文件)命令效果完全一样。也可以用
gdb
去检查一个因程序异常终止而产生的
core
文件,或者与一个正在运行的程序相连。

gdb
支持很多的命令且能实现不同的功能,这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令。

1
,编辑源文件。

例如,
vi 1-9

添加如下内容

#include <stdio.h>

int min(int x, int y);

int main()

{

int
a1, a2, min_int;

printf("please input the frist int number:/n");

scanf("%d", &a1);

printf("please input the second int number:/n");

scanf("%d", &a2);

min_int = min(a1, a2);

printf("the min number is:%d/n", min_int);

return 0;

}

int min(int x, int y)

{

if
(x < y)

return x;

else

return y;

}

2
,编译时要加上选项“
-g
”,这样编译出的可执行代码才包含调试信息。

gcc 1-9.c -o 1-9 -g

3
,进入
gdb
调试环境。

gdb 1-9

回车就进入了
gdb
调试模式。在
gdb
的调试环境中,提示符是“
(gdb)
”。

4
,用
gdb
调试程序。

(1)
查看源文件

语法:
'l'

list
缩写。
list<
行号
>|<
函数名
>
。查看源代码,一次显示
10


命令

(gdb)l

(2)
设置断点

语法:
break
行号
|
函数名
<
条件表达式
>

本例可以输入命令

(gdb)b min

在自定义的
min
函数出设置断点。

(gdb)b 17

功能同上

(3)
查看断点信息

语法:
info break
# info
命令是显示
XX
信息,常用有
files,func,local,proc.

命令

(gdb)info b

(4)
运行程序

语法:
run
#
执行当前被调试的程序

命令

(gdb)r

注:
gdb
默认从第一行开始运行,如果要从出现中指定行开始运行,只需输入“
r

+
行号。

(5)
查看变量值

语法:
p
变量名。程序运行到断点处会自动暂停,此时可查看指定变量的值。

本例命令

(gdb)p a1

(gdb)p a2

(gdb)p min_int

调试程序时,如需修改变量值,可在程序运行至断点处是,输入“
set
变量
=
设定值”。

例,给变量“
a2
”赋值
11
,输入“
set a2=11
”。

(6)
单步调试

语法:


n

(next)
,若有函数,不进入函数调用。


s

(step)
,若有函数,则进入函数调用。

(7)
继续运行程序

语法:
continue

命令

(gdb)c

(8)
退出
gdb
调试环境。

语法:
quit

命令

(gdb)q

其他常用命令还有:

Tbreak

命令:

设置临时断点。它的语法与
break
相同。区别在于用
tbreak
设置的断点执行一次之后立即消失。

watch

命令

:设置监视点,监视表达式的变化。

awatch
命令:设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与
watch
命令相同。

rwatch
命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与
watch
相同。

display

命令:

在应用程序每次停止运行时显示表达式的值。

print

命令:

显示表达式的值。

delete

命令:

删除断点。指定一个断点号码,则删除指定断点。不指定参数则删除所有的断点。

Shell

命令:

执行
Linux Shell
命令。

make

命令:

不退出
gdb
而重新编译生成可执行文件。

注:这些指令可以在以后使用过程中查,不必死记硬背。以后用得多了,自然就会记住。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: