GDB调试.pdf
2011年05月26日
1.1 Gdb调试器
调试是所有程序员都会面临的问题。如何提高程序员的调试效率,更好更快地定位程序
中的问题从而加快程序开发的进度,是大家共同要面对问题。就如读者熟知的Windows 下
的一些调试工具,如VC 自带的如设置断点、单步跟踪等,都受到了广大用户的赞赏。那么,
在Linux 下有什么很好的调试工具呢?
本文所介绍的Gdb 调试器是一款GNU 开发组织并发布的UNIX/Linux 下的程序调试
工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的VC 工具等媲
美。
下面就请跟随笔者一步步学习Gdb 调试器。
1.1.1 Gdb 使用流程
这里给出了一个短小的程序,由此带领读者熟悉一下Gdb 的使用流程。建议读者能够
实际动手操作。
首先,打开Linux 下的编辑器Vi,编辑如下代码。
/************************************************* *********
Copyright (C), 2001-2011, GEC Co., Ltd.
File Name : net_parse.c
Version : Initial Draft
Author : liuzhigang
Created : 2010/5/3
Description : 网络模块解析网络数据的文件
History :
1.Date : 2010/5/3
Author : liuzhigang
Modification: Created file
************************************************** ********/
#include
int sum(int m);
int main()
{ int i,n=0;
sum(50);
for(i=1; i
int sum(int m);
/************************************************* *********
Prototype : main
Description : ????
Input : None
Output : None
Return Value :
************************************************** ********/
int main()
{
int i, n = 0;
int ret;
/* xxxxxxxxxxxxxxxxxxxxxx */
ret = sum(50);
if (0 != ret)
{
printf("sum funciton error!\n");
return -1;
}
for(i = 1; i 代码中才包含调试信息,否则之后Gdb 无法载入该可执行文件。
# gcc -g test.c -o test
虽然这段程序没有错误,但调试完全正确的程序可以更加了解Gdb 的使用流程。接下
来就是启动Gdb 进行调试。注意,Gdb 进行调试的是可执行文件,而不是如".c"的源代码,
因此,需要先通过Gcc 编译生成可执行文件才能用Gdb 进行调试。
# gdb test
GNU Gdb Red Hat Linux (6.3.0.0-1.21rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License,
and you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host
libthread_db
library "/lib/libthread_db.so.1".
(gdb)
可以看出,在Gdb 的启动画面中指出了Gdb 的版本号、使用的库文件等信息,接下来
就进入了由"(gdb)"开头的命令行界面了。
1. 查看文件
在Gdb 中键入"l"(list)就可以查看所载入的文件,如下所示:
注意
在Gdb 的命令中都可使用缩略形式的命令,如"l"代便"list","b"代表"breakpoint","p"
代表"print"等,读者也可使用"help"命令来查看帮助信息。
(Gdb) l
1 #include
2 int sum(int m);
3 int main()
4 {
5 int i,n=0;
6 sum(50);
7 for(i=1; i代码的症结所
在。在Gdb 中设置断点非常简单,只需在"b"后加入对应的行号即可(这是最常用的方式,
另外还有其他方式设置断点)。如下所示:
(Gdb) b 6
Breakpoint 1 at 0x804846d: file test.c, line 6.
要注意的是,在Gdb 中利用行号设置断点是指代码运行到对应行之前将其停止,如上
例中,代码运行到第5 行之前就暂停(并没有运行第5 行)。
3. 查看断点情况
在设置完断点之后,用户可以键入"info b"来查看设置断点的情况,在Gdb 中可以设置
多个断点。
(Gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804846d in main at test.c:6
4. 运行代码
接下来就可运行代码,Gdb 默认从首行开始运行代码,可键入"r"(run)即可(若想从
程序中指定行开始运行,可在r 后面加上行号)。
(Gdb) r
Starting program: /root/workplace/Gdb/test
Reading symbols from shared object read from target memory done.
Loaded system supplied DSO at 0x5fb000
Breakpoint 1, main () at test.c:6
6 sum(50);
可以看到,程序运行到断点处就停止了。
5. 查看变量值
在程序停止运行之后,程序员所要做的工作是查看断点处的相关的变量值。在Gdb 中
只需键入"p"+变量值即可,如下所示:
(Gdb) p n
$1 = 0
(Gdb) p i
$2 = 134518440
在此处,为什么变量"i"的值为如此奇怪的一个数字呢?原因就在于程序是在断点设置
的对应行之前停止的,那么在此时,并没把"i"的数值赋为零,而只是一个随机的数字。但
变量"n"是在第四行赋值的,故在此时已经为零。
小技巧
Gdb 在显示变量值时都会在对应值之前加上"$N"标记,它是当前变量值的引用标记,
所以以后若想再次引用此变量就可以直接写作"$N",而无需写冗长的变量名。
6. 单步运行
单步运行可以使用命令"n"(next)或"s"(step),它们之间的区别是:若有函数调用的
时候,"s"会进入该函数而"n"不会进入该函数。因此,"s"就类似于VC 等工具中的"step in",
"n"类似与VC 等工具中的"step over"。它们的使用如下所示:
(Gdb) n
The sum of 1-m is 1275
7 for(i=1; i代码查看命令、查看运行数据相关命令及修改运行参数命令。以下就分别对这几类的命令进
行讲解。
1. 工作环境相关命令
Gdb 中不仅可以调试所运行的程序,而且还可以对程序相关的工作环境进行相应的设
定,甚至还可以使用shell 中的命令进行相关的操作,其功能极其强大。Gdb 的常见工作环
境相关命令如表3 8 所示。
表3 8 Gdb 工作相关命令
命令格式含义
set args 运行时的参数指定运行时参数,如set args 2
show args 查看设置好的运行参数
path dir 设定程序的运行路径
show paths 查看程序的运行路径
set enVironment var [=value] 设置环境变量
show enVironment [var] 查看环境变量
cd dir 进入到dir 目录,相当于shell 中的cd 命令
pwd 显示当前工作目录
shell command 运行shell 的command 命令
2. 设置断点与恢复命令
Gdb 中设置断点与恢复的常见命令如表3 9 所示。
表3 9 Gdb 设置断点与恢复相关命令
命令格式含义
bnfo b 查看所设断点
break 行号或函数名 设置断点
tbreak 行号或函数名 设置临时断点,到达后被自动删除
delete [断点号]
删除指定断点,其断点号为"info b"中的第一
栏。若缺省断点号则删除所有断点
disable [断点号]]
停止指定断点,使用"info b"仍能查看此断点。同
delete 一样,省断点号则停止所有断点
enable [断点号] 激活指定断点,即激活被disable 停止的断点
condition [断点号] 修改对应断点的条件
ignore [断点号] 在程序执行中,忽略对应断点num 次
step 单步恢复程序运行,且进入函数调用
next 单步恢复程序运行,但不进入函数调用
finish 运行程序,直到当前函数完成返回
c 继续执行函数,直到函数结束或遇到新的断点
由于设置断点在Gdb 的调试中非常重要,所以在此再着重讲解一下Gdb 中设置断点的
方法。Gdb 中设置断点有多种方式:其一是按行设置断点,设置方法在前面已经指出,在
此就不重复了。另外还可以设置函数断点和条件断点,在此结合上一小节的代码,具体介绍
后两种设置断点的方法。
① 函数断点
Gdb 中按函数设置断点只需要把函数名列在命令"b"之后,如下所示:
(gdb) b sum
Breakpoint 1 at 0x80484ba: file test.c, line 16.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484ba in sum at test.c:16
要注意的是,此时的断点实际是在函数的定义处,也就是在16 行处(注意第16 行还
未执行)。
② 条件断点
Gdb 中设置条件断点的格式为:b 行数或函数名if 表达式。具体实例如下面所示:
(gdb) b 8 if i==10
Breakpoint 1 at 0x804848c: file test.c, line 8.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804848c in main at test.c:8
stop only if i == 10
(gdb) r
Starting program: /home/yul/test
The sum of 1-m is 1275
Breakpoint 1, main () at test.c:9
9 n += i;
(gdb) p i
$1 = 10
可以看到,该例中在第8 行(也就是运行完第7 行的for 循环)设置了一个"i==0"的条
件断点,在程序运行之后可以看出,程序确实在i 为10 的时候暂停运行。
3. Gdb中源码查看相关命令
在Gdb 中可以查看源码以方便其他操作,它的常见相关命令如表3 10 所示。
表3 10 Gdb 源码查看相关命令
命令格式含义
list | 查看指定位置代码
file [文件名] 加载指定文件
forward-search 正则表达式源代码前向搜索
reverse-search 正则表达式源代码后向搜索
dir dir 停止路径名
show directories 显示定义了的源文件搜索路径
info line 显示加载到Gdb 内存中的代码
4. Gdb 中查看运行数据相关命令
Gdb 中查看运行数据是指当程序处于"运行"或"暂停"状态时,可以查看的变量及表达式
的信息,其常见命令如表3 11 所示:
表3 11 Gdb 查看运行数据相关命令
命令格式含义
print 表达式|变量查看程序运行时对应表达式和变量的值
x
查看内存变量内容。其中n 为整数表示显示内存的长度,f
表示显示的格式,u 表示从当前地址往后请求显示的字节数
display 表达式
设定在单步运行或其他情况中,自动显示的对应表达式的内
容
5. Gdb 中修改运行参数相关命令
Gdb 还可以修改运行时的参数,并使该变量按照用户当前输入值继续运行。它的设置
方式为:在单步执行的过程中,键入命令"set 变量=设定值"。这样,在此之后,程序就会
按照该设定的值运行了。下面,笔者结合上一节的代码将n 的初始值设为4,其代码如下所
示:
(Gdb) b 7
Breakpoint 5 at 0x804847a: file test.c, line 7.
(Gdb) r
Starting program: /home/yul/test
The sum of 1-m is 1275
Breakpoint 5, main () at test.c:7
7 for(i=1; i代码处于"运行"或"暂停"状态时才能查看变量值。
设置断点后程序在指定行之前停止。
1.1.3 用Gdb 调试有问题的程序
1. 实验目的
通过调试一个有问题的程序,使读者进一步熟练使用Vi 操作,而且熟练掌握Gcc 编
译命令及Gdb 的调试命令,通过对有问题程序的跟踪调试,进一步提高发现问题和解决问
题的能力。这是一个很小的程序,只有35 行,希望读者能够认真调试。
2. 实验内容
(1)使用Vi 编辑器,将以下代码输入到名为greet.c 的文件中。此代码的原意为输出
倒序main 函数中定义的字符串,但其结果显示没有输出。代码如下所示:
#include
int display1(char *string);
int display2(char *string);
int main ()
{ char string[] =
"
Embedded Linux";
display1 (string);
display2 (string);
} int display1 (
char *
string)
{ printf ("The original string is %
s
\
n", string);
} int display2 (
char *string1)
{ char *
string2;
int size,i;
size = strlen (string1);
string2 = (char *) malloc (size + 1);
for (i = 0; i 代码,注意要加上"-g"选项方便之后的调试。
(3)运行生成的可执行文件,观察其运行结果。
(4)使用Gdb 调试程序,通过设置断点、单步跟踪,一步步找出错误所在。
(5)纠正错误,更改源程序并得到正确的结果。
3. 实验步骤
(1)在工作目录上新建文件greet.c,并用Vi 启动:vi greet.c。
(2)在Vi 中输入以上代码。
(3)在Vi 中保存并退出:wq。
(4)用Gcc 进行编译:gcc -g greet.c -o greet。
(5)运行greet:./greet,输出为:
The original string is Embedded Linux
The string afterward is
可见,该程序没有能够倒序输出。
(6)启动Gdb 调试:gdb greet。
(7)查看源代码,使用命令"l"。
(8)在30 行(for 循环处)设置断点,使用命令"b 30"。
(9)在33 行(printf 函数处)设置断点,使用命令"b 33"。
(10)查看断点处设置情况,使用命令"info b"。
(11)运行代码,使用命令"r"。
(12)单步运行代码,使用命令"n"。
(13)查看暂停点变量值,使用命令"p string2[size - i]"。
(14)继续单步运行代码数次,并使用命令查看,发现string2[size-1]的值正确。
(15)继续程序的运行,使用命令"c"。
(16)程序在printf 前停止运行,此时依次查看string2[0]、string2[1]…,发现string[0]
并没有被正确赋值,而后面的复制都是正确的,这时,定位程序第31 行,发现程序运行结
果错误的原因在于"size-1"。由于i 只能增到"size-1",这样string2[0]就永远不能被赋值而保
持NULL,故输不出任何结果。
(17)退出Gdb,使用命令q。
(18)重新编辑greet.c,把其中的"string2[size - i] = string1[i]"改为"string2[size i - 1]
=string1[i];"即可。
(19)使用Gcc 重新编译:gcc -g greet.c -o greet。
(20)查看运行结果:./greet
The original string is Embedded Linux
The string afterward is xuniL deddedbmE
这时,正确输出结果。
4. 实验结果
将原来有错的程序经过Gdb 调试,找出问题所在,并修改源代码,输出正确的倒序显
示字符串的结果。
2011年05月26日
1.1 Gdb调试器
调试是所有程序员都会面临的问题。如何提高程序员的调试效率,更好更快地定位程序
中的问题从而加快程序开发的进度,是大家共同要面对问题。就如读者熟知的Windows 下
的一些调试工具,如VC 自带的如设置断点、单步跟踪等,都受到了广大用户的赞赏。那么,
在Linux 下有什么很好的调试工具呢?
本文所介绍的Gdb 调试器是一款GNU 开发组织并发布的UNIX/Linux 下的程序调试
工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的VC 工具等媲
美。
下面就请跟随笔者一步步学习Gdb 调试器。
1.1.1 Gdb 使用流程
这里给出了一个短小的程序,由此带领读者熟悉一下Gdb 的使用流程。建议读者能够
实际动手操作。
首先,打开Linux 下的编辑器Vi,编辑如下代码。
/************************************************* *********
Copyright (C), 2001-2011, GEC Co., Ltd.
File Name : net_parse.c
Version : Initial Draft
Author : liuzhigang
Created : 2010/5/3
Description : 网络模块解析网络数据的文件
History :
1.Date : 2010/5/3
Author : liuzhigang
Modification: Created file
************************************************** ********/
#include
int sum(int m);
int main()
{ int i,n=0;
sum(50);
for(i=1; i
int sum(int m);
/************************************************* *********
Prototype : main
Description : ????
Input : None
Output : None
Return Value :
************************************************** ********/
int main()
{
int i, n = 0;
int ret;
/* xxxxxxxxxxxxxxxxxxxxxx */
ret = sum(50);
if (0 != ret)
{
printf("sum funciton error!\n");
return -1;
}
for(i = 1; i 代码中才包含调试信息,否则之后Gdb 无法载入该可执行文件。
# gcc -g test.c -o test
虽然这段程序没有错误,但调试完全正确的程序可以更加了解Gdb 的使用流程。接下
来就是启动Gdb 进行调试。注意,Gdb 进行调试的是可执行文件,而不是如".c"的源代码,
因此,需要先通过Gcc 编译生成可执行文件才能用Gdb 进行调试。
# gdb test
GNU Gdb Red Hat Linux (6.3.0.0-1.21rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License,
and you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host
libthread_db
library "/lib/libthread_db.so.1".
(gdb)
可以看出,在Gdb 的启动画面中指出了Gdb 的版本号、使用的库文件等信息,接下来
就进入了由"(gdb)"开头的命令行界面了。
1. 查看文件
在Gdb 中键入"l"(list)就可以查看所载入的文件,如下所示:
注意
在Gdb 的命令中都可使用缩略形式的命令,如"l"代便"list","b"代表"breakpoint","p"
代表"print"等,读者也可使用"help"命令来查看帮助信息。
(Gdb) l
1 #include
2 int sum(int m);
3 int main()
4 {
5 int i,n=0;
6 sum(50);
7 for(i=1; i代码的症结所
在。在Gdb 中设置断点非常简单,只需在"b"后加入对应的行号即可(这是最常用的方式,
另外还有其他方式设置断点)。如下所示:
(Gdb) b 6
Breakpoint 1 at 0x804846d: file test.c, line 6.
要注意的是,在Gdb 中利用行号设置断点是指代码运行到对应行之前将其停止,如上
例中,代码运行到第5 行之前就暂停(并没有运行第5 行)。
3. 查看断点情况
在设置完断点之后,用户可以键入"info b"来查看设置断点的情况,在Gdb 中可以设置
多个断点。
(Gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804846d in main at test.c:6
4. 运行代码
接下来就可运行代码,Gdb 默认从首行开始运行代码,可键入"r"(run)即可(若想从
程序中指定行开始运行,可在r 后面加上行号)。
(Gdb) r
Starting program: /root/workplace/Gdb/test
Reading symbols from shared object read from target memory done.
Loaded system supplied DSO at 0x5fb000
Breakpoint 1, main () at test.c:6
6 sum(50);
可以看到,程序运行到断点处就停止了。
5. 查看变量值
在程序停止运行之后,程序员所要做的工作是查看断点处的相关的变量值。在Gdb 中
只需键入"p"+变量值即可,如下所示:
(Gdb) p n
$1 = 0
(Gdb) p i
$2 = 134518440
在此处,为什么变量"i"的值为如此奇怪的一个数字呢?原因就在于程序是在断点设置
的对应行之前停止的,那么在此时,并没把"i"的数值赋为零,而只是一个随机的数字。但
变量"n"是在第四行赋值的,故在此时已经为零。
小技巧
Gdb 在显示变量值时都会在对应值之前加上"$N"标记,它是当前变量值的引用标记,
所以以后若想再次引用此变量就可以直接写作"$N",而无需写冗长的变量名。
6. 单步运行
单步运行可以使用命令"n"(next)或"s"(step),它们之间的区别是:若有函数调用的
时候,"s"会进入该函数而"n"不会进入该函数。因此,"s"就类似于VC 等工具中的"step in",
"n"类似与VC 等工具中的"step over"。它们的使用如下所示:
(Gdb) n
The sum of 1-m is 1275
7 for(i=1; i代码查看命令、查看运行数据相关命令及修改运行参数命令。以下就分别对这几类的命令进
行讲解。
1. 工作环境相关命令
Gdb 中不仅可以调试所运行的程序,而且还可以对程序相关的工作环境进行相应的设
定,甚至还可以使用shell 中的命令进行相关的操作,其功能极其强大。Gdb 的常见工作环
境相关命令如表3 8 所示。
表3 8 Gdb 工作相关命令
命令格式含义
set args 运行时的参数指定运行时参数,如set args 2
show args 查看设置好的运行参数
path dir 设定程序的运行路径
show paths 查看程序的运行路径
set enVironment var [=value] 设置环境变量
show enVironment [var] 查看环境变量
cd dir 进入到dir 目录,相当于shell 中的cd 命令
pwd 显示当前工作目录
shell command 运行shell 的command 命令
2. 设置断点与恢复命令
Gdb 中设置断点与恢复的常见命令如表3 9 所示。
表3 9 Gdb 设置断点与恢复相关命令
命令格式含义
bnfo b 查看所设断点
break 行号或函数名 设置断点
tbreak 行号或函数名 设置临时断点,到达后被自动删除
delete [断点号]
删除指定断点,其断点号为"info b"中的第一
栏。若缺省断点号则删除所有断点
disable [断点号]]
停止指定断点,使用"info b"仍能查看此断点。同
delete 一样,省断点号则停止所有断点
enable [断点号] 激活指定断点,即激活被disable 停止的断点
condition [断点号] 修改对应断点的条件
ignore [断点号] 在程序执行中,忽略对应断点num 次
step 单步恢复程序运行,且进入函数调用
next 单步恢复程序运行,但不进入函数调用
finish 运行程序,直到当前函数完成返回
c 继续执行函数,直到函数结束或遇到新的断点
由于设置断点在Gdb 的调试中非常重要,所以在此再着重讲解一下Gdb 中设置断点的
方法。Gdb 中设置断点有多种方式:其一是按行设置断点,设置方法在前面已经指出,在
此就不重复了。另外还可以设置函数断点和条件断点,在此结合上一小节的代码,具体介绍
后两种设置断点的方法。
① 函数断点
Gdb 中按函数设置断点只需要把函数名列在命令"b"之后,如下所示:
(gdb) b sum
Breakpoint 1 at 0x80484ba: file test.c, line 16.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484ba in sum at test.c:16
要注意的是,此时的断点实际是在函数的定义处,也就是在16 行处(注意第16 行还
未执行)。
② 条件断点
Gdb 中设置条件断点的格式为:b 行数或函数名if 表达式。具体实例如下面所示:
(gdb) b 8 if i==10
Breakpoint 1 at 0x804848c: file test.c, line 8.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804848c in main at test.c:8
stop only if i == 10
(gdb) r
Starting program: /home/yul/test
The sum of 1-m is 1275
Breakpoint 1, main () at test.c:9
9 n += i;
(gdb) p i
$1 = 10
可以看到,该例中在第8 行(也就是运行完第7 行的for 循环)设置了一个"i==0"的条
件断点,在程序运行之后可以看出,程序确实在i 为10 的时候暂停运行。
3. Gdb中源码查看相关命令
在Gdb 中可以查看源码以方便其他操作,它的常见相关命令如表3 10 所示。
表3 10 Gdb 源码查看相关命令
命令格式含义
list | 查看指定位置代码
file [文件名] 加载指定文件
forward-search 正则表达式源代码前向搜索
reverse-search 正则表达式源代码后向搜索
dir dir 停止路径名
show directories 显示定义了的源文件搜索路径
info line 显示加载到Gdb 内存中的代码
4. Gdb 中查看运行数据相关命令
Gdb 中查看运行数据是指当程序处于"运行"或"暂停"状态时,可以查看的变量及表达式
的信息,其常见命令如表3 11 所示:
表3 11 Gdb 查看运行数据相关命令
命令格式含义
print 表达式|变量查看程序运行时对应表达式和变量的值
x
查看内存变量内容。其中n 为整数表示显示内存的长度,f
表示显示的格式,u 表示从当前地址往后请求显示的字节数
display 表达式
设定在单步运行或其他情况中,自动显示的对应表达式的内
容
5. Gdb 中修改运行参数相关命令
Gdb 还可以修改运行时的参数,并使该变量按照用户当前输入值继续运行。它的设置
方式为:在单步执行的过程中,键入命令"set 变量=设定值"。这样,在此之后,程序就会
按照该设定的值运行了。下面,笔者结合上一节的代码将n 的初始值设为4,其代码如下所
示:
(Gdb) b 7
Breakpoint 5 at 0x804847a: file test.c, line 7.
(Gdb) r
Starting program: /home/yul/test
The sum of 1-m is 1275
Breakpoint 5, main () at test.c:7
7 for(i=1; i代码处于"运行"或"暂停"状态时才能查看变量值。
设置断点后程序在指定行之前停止。
1.1.3 用Gdb 调试有问题的程序
1. 实验目的
通过调试一个有问题的程序,使读者进一步熟练使用Vi 操作,而且熟练掌握Gcc 编
译命令及Gdb 的调试命令,通过对有问题程序的跟踪调试,进一步提高发现问题和解决问
题的能力。这是一个很小的程序,只有35 行,希望读者能够认真调试。
2. 实验内容
(1)使用Vi 编辑器,将以下代码输入到名为greet.c 的文件中。此代码的原意为输出
倒序main 函数中定义的字符串,但其结果显示没有输出。代码如下所示:
#include
int display1(char *string);
int display2(char *string);
int main ()
{ char string[] =
"
Embedded Linux";
display1 (string);
display2 (string);
} int display1 (
char *
string)
{ printf ("The original string is %
s
\
n", string);
} int display2 (
char *string1)
{ char *
string2;
int size,i;
size = strlen (string1);
string2 = (char *) malloc (size + 1);
for (i = 0; i 代码,注意要加上"-g"选项方便之后的调试。
(3)运行生成的可执行文件,观察其运行结果。
(4)使用Gdb 调试程序,通过设置断点、单步跟踪,一步步找出错误所在。
(5)纠正错误,更改源程序并得到正确的结果。
3. 实验步骤
(1)在工作目录上新建文件greet.c,并用Vi 启动:vi greet.c。
(2)在Vi 中输入以上代码。
(3)在Vi 中保存并退出:wq。
(4)用Gcc 进行编译:gcc -g greet.c -o greet。
(5)运行greet:./greet,输出为:
The original string is Embedded Linux
The string afterward is
可见,该程序没有能够倒序输出。
(6)启动Gdb 调试:gdb greet。
(7)查看源代码,使用命令"l"。
(8)在30 行(for 循环处)设置断点,使用命令"b 30"。
(9)在33 行(printf 函数处)设置断点,使用命令"b 33"。
(10)查看断点处设置情况,使用命令"info b"。
(11)运行代码,使用命令"r"。
(12)单步运行代码,使用命令"n"。
(13)查看暂停点变量值,使用命令"p string2[size - i]"。
(14)继续单步运行代码数次,并使用命令查看,发现string2[size-1]的值正确。
(15)继续程序的运行,使用命令"c"。
(16)程序在printf 前停止运行,此时依次查看string2[0]、string2[1]…,发现string[0]
并没有被正确赋值,而后面的复制都是正确的,这时,定位程序第31 行,发现程序运行结
果错误的原因在于"size-1"。由于i 只能增到"size-1",这样string2[0]就永远不能被赋值而保
持NULL,故输不出任何结果。
(17)退出Gdb,使用命令q。
(18)重新编辑greet.c,把其中的"string2[size - i] = string1[i]"改为"string2[size i - 1]
=string1[i];"即可。
(19)使用Gcc 重新编译:gcc -g greet.c -o greet。
(20)查看运行结果:./greet
The original string is Embedded Linux
The string afterward is xuniL deddedbmE
这时,正确输出结果。
4. 实验结果
将原来有错的程序经过Gdb 调试,找出问题所在,并修改源代码,输出正确的倒序显
示字符串的结果。