📄 csdn_文档中心_用 gdb 调试程序.htm
字号:
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR></TBODY></TABLE><!--文章说明信息结束//-->
<TABLE border=0 width=600>
<TBODY>
<TR>
<TD align=left><BR>用 GDB 调试程序 <BR><BR>用 gdb 调试 GCC 程序<BR>
Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器.
它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的一些功能: <BR>它使你能监视你程序中变量的值.
<BR>它使你能设置断点以使程序在指定的代码行上停止执行. <BR>它使你能一行行的执行你的代码. <BR><BR>
在命令行上键入 gdb 并按回车键就可以运行 gdb 了, 如果一切正常的话, gdb
将被启动并且你将在屏幕上看到类似的内容: <BR>GDB is free software and you are welcome to
distribute copies of it<BR><BR>under certain conditions; type "show
copying" to see the conditions.<BR><BR>There is absolutely no
warranty for GDB; type "show warranty" for details.<BR><BR>GDB 4.14
(i486-slakware-linux), Copyright 1995 Free Software Foundation,
Inc.<BR><BR>(gdb)<BR> 当你启动 gdb 后, 你能在命令行上指定很多的选项.
你也可以以下面的方式来运行 gdb : <BR>gdb <fname><BR> 当你用这种方式运行
gdb , 你能直接指定想要调试的程序. 这将告诉gdb 装入名为 fname 的可执行文件. 你也可以用 gdb
去检查一个因程序异常终止而产生的 core 文件, 或者与一个正在运行的程序相连. 你可以参考 gdb 指南页或在命令行上键入 gdb
-h 得到一个有关这些选项的说明的简单列表. <BR> <BR>为调试编译代码(Compiling Code for
Debugging)<BR> 为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息.
调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号. gdb
利用这些信息使源代码和机器码相关联. <BR> 在编译时用 -g 选项打开调试选项. <BR>
<BR><BR>gdb 基本命令<BR> gdb 支持很多的命令使你能实现不同的功能.
这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 gdb 调试时会用到的一些命令. 想了解
gdb 的详细使用请参考 gdb 的指南页. <BR> <BR><BR>表 27.1. 基本 gdb
命令.<BR><BR>命 令 描 述 <BR>file 装入想要调试的可执行文件. <BR>kill
终止正在调试的程序. <BR>list 列出产生执行文件的源代码的一部分. <BR>next 执行一行源代码但不进入函数内部.
<BR>step 执行一行源代码而且进入函数内部. <BR>run 执行当前被调试的程序 <BR>quit 终止 gdb
<BR>watch 使你能监视一个变量的值而不管它何时被改变. <BR>break 在代码里设置断点, 这将使程序执行到这里时被挂起.
<BR>make 使你能不退出 gdb 就可以重新产生可执行文件. <BR>shell 使你能不离开 gdb 就执行 UNIX
shell 命令. <BR><BR> <BR> <BR> gdb
支持很多与 UNIX shell 程序一样的命令编辑特征. 你能象在 bash 或 tcsh里那样按 Tab 键让 gdb
帮你补齐一个唯一的命令, 如果不唯一的话 gdb 会列出所有匹配的命令. 你也能用光标键上下翻动历史命令. <BR><BR>gdb
应用举例<BR> 本节用一个实例教你一步步的用 gdb 调试程序. 被调试的程序相当的简单, 但它展示了
gdb 的典型应用. <BR> <BR> 下面列出了将被调试的程序. 这个程序被称为
greeting , 它显示一个简单的问候, 再用反序将它列出. <BR>#include
<stdio.h><BR><BR><BR><BR>main ()<BR><BR>{<BR><BR> char
my_string[] = "hello there";<BR><BR><BR><BR> my_print
(my_string);<BR><BR> my_print2
(my_string);<BR><BR>}<BR><BR><BR><BR>void my_print (char
*string)<BR><BR>{<BR><BR> printf ("The string is %s\n",
string);<BR><BR>}<BR><BR><BR><BR>void my_print2 (char
*string)<BR><BR>{<BR><BR> char *string2;<BR><BR> int
size, i;<BR><BR><BR><BR> size = strlen (string);<BR><BR>
string2 = (char *) malloc (size + 1);<BR><BR> for (i = 0; i
< size; i++)<BR><BR> string2[size - i] =
string[i];<BR><BR> string2[size+1] = `\0';<BR><BR>
printf ("The string printed backward is %s\n",
string2);<BR><BR>}<BR> 用下面的命令编译它: <BR> <BR>gcc -o
test test.c<BR> 这个程序执行时显示如下结果: <BR>The string is hello
there<BR><BR>The string printed backward is<BR>
输出的第一行是正确的, 但第二行打印出的东西并不是我们所期望的. 我们所设想的输出应该是: <BR>The string printed
backward is ereht olleh<BR> 由于某些原因, my_print2 函数没有正常工作.
让我们用 gdb 看看问题究竟出在哪儿, 先键入如下命令: <BR> <BR>gdb
greeting<BR><BR>--------------------------------------------------------------------------------<BR>注意:
记得在编译 greeting 程序时把调试选项打开.
<BR>--------------------------------------------------------------------------------<BR><BR>
如果你在输入命令时忘了把要调试的程序作为参数传给 gdb , 你可以在 gdb 提示符下用 file 命令来载入它:
<BR> <BR>(gdb) file greeting<BR> 这个命令将载入 greeting
可执行文件就象你在 gdb 命令行里装入它一样. <BR> 这时你能用 gdb 的 run 命令来运行
greeting 了. 当它在 gdb 里被运行后结果大约会象这样: <BR><BR>(gdb) run<BR><BR>Starting
program: /root/greeting<BR><BR>The string is hello there<BR><BR>The
string printed backward is<BR><BR>Program exited with code
041<BR> 这个输出和在 gdb 外面运行的结果一样. 问题是, 为什么反序打印没有工作?
为了找出症结所在, 我们可以在 my_print2 函数的 for 语句后设一个断点, 具体的做法是在 gdb 提示符下键入 list
命令三次, 列出源代码: <BR>(gdb) list<BR><BR>(gdb) list<BR><BR>(gdb)
list<BR><BR>--------------------------------------------------------------------------------<BR>技巧:
在 gdb 提示符下按回车健将重复上一个命令.
<BR>--------------------------------------------------------------------------------<BR><BR>
第一次键入 list 命令的输出如下: <BR> <BR>1
#include <stdio.h><BR><BR>2<BR><BR>3
main ()<BR><BR>4 {<BR><BR>5
char my_string[] = "hello there";<BR><BR>6<BR><BR>7
my_print (my_string);<BR><BR>8
my_print2 (my_string);<BR><BR>9
}<BR><BR>10<BR> 如果按下回车, gdb 将再执行一次 list 命令, 给出下列输出:
<BR> <BR>11 my_print (char
*string)<BR><BR>12 {<BR><BR>13
printf ("The string is %s\n", string);<BR><BR>14
}<BR><BR>15<BR><BR>16 my_print2
(char *string)<BR><BR>17 {<BR><BR>18
char *string2;<BR><BR>19
int size, i;<BR><BR>20<BR> 再按一次回车将列出 greeting
程序的剩余部分: <BR>21 size = strlen
(string);<BR><BR>22 string2 = (char *)
malloc (size + 1);<BR><BR>23 for (i = 0;
i < size; i++)<BR><BR>24
string2[size - i] = string[i];<BR><BR>25
string2[size+1] = `\0';<BR><BR>26 printf
("The string printed backward is %s\n", string2);<BR><BR>27
}<BR> 根据列出的源程序, 你能看到要设断点的地方在第24行, 在 gdb
命令行提示符下键入如下命令设置断点: <BR>(gdb) break 24<BR> gdb 将作出如下的响应:
<BR>Breakpoint 1 at 0x139: file greeting.c, line
24<BR><BR>(gdb)<BR> <BR> 现在再键入 run 命令, 将产生如下的输出:
<BR> <BR>Starting program: /root/greeting<BR><BR>The string is
hello there<BR><BR><BR><BR>Breakpoint 1, my_print2 (string =
0xbfffdc4 "hello there") at greeting.c :24<BR><BR>24
string2[size-i]=string[i]<BR> 你能通过设置一个观察 string2[size -
i] 变量的值的观察点来看出错误是怎样产生的, 做法是键入: <BR> <BR>(gdb) watch
string2[size - i]<BR> gdb 将作出如下回应: <BR>Watchpoint 2:
string2[size - i]<BR> 现在可以用 next 命令来一步步的执行 for 循环了:
<BR> <BR>(gdb) next<BR> 经过第一次循环后, gdb 告诉我们
string2[size - i] 的值是 `h`. gdb 用如下的显示来告诉你这个信息: <BR>
<BR>Watchpoint 2, string2[size - i]<BR><BR>Old value = 0
`\000'<BR><BR>New value = 104 `h'<BR><BR>my_print2(string =
0xbfffdc4 "hello there") at greeting.c:23<BR><BR>23 for (i=0;
i<size; i++)<BR> 这个值正是期望的. 后来的数次循环的结果都是正确的. 当 i=10
时, 表达式 string2[size - i] 的值等于 `e`, size - i 的值等于 1,
最后一个字符已经拷到新串里了. <BR> 如果你再把循环执行下去, 你会看到已经没有值分配给
string2[0] 了, 而它是新串的第一个字符, 因为 malloc 函数在分配内存时把它们初始化为空(null)字符.
所以 string2 的第一个字符是空字符. 这解释了为什么在打印 string2 时没有任何输出了. <BR><BR>
现在找出了问题出在哪里, 修正这个错误是很容易的. 你得把代码里写入 string2 的第一个字符的的偏移量改为 size
- 1 而不是 size. 这是因为 string2 的大小为 12, 但起始偏移量是 0, 串内的字符从偏移量 0 到 偏移量 10,
偏移量 11 为空字符保留. <BR><BR> 为了使代码正常工作有很多种修改办法.
一种是另设一个比串的实际大小小 1 的变量. 这是这种解决办法的代码: <BR><BR>#include
<stdio.h><BR><BR><BR><BR>main ()<BR><BR><BR>{<BR><BR>
char my_string[] = "hello there";<BR><BR><BR><BR> my_print
(my_string);<BR><BR> my_print2
(my_string);<BR><BR>}<BR><BR><BR><BR>my_print (char
*string)<BR><BR>{<BR><BR> printf ("The string is %s\n",
string);<BR><BR>}<BR><BR><BR><BR>my_print2 (char
*string)<BR><BR>{<BR><BR> char *string2;<BR><BR> int
size, size2, i;<BR><BR><BR><BR> size = strlen
(string);<BR><BR> size2 = size -1;<BR><BR> string2 =
(char *) malloc (size + 1);<BR><BR> for (i = 0; i < size;
i++)<BR><BR> string2[size2 - i] =
string[i];<BR><BR> string2[size] = `\0';<BR><BR> printf
("The string printed backward is %s\n",
string2);<BR><BR>}<BR><BR>
<BR><BR></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
<TABLE align=center bgColor=#006699 border=0 cellPadding=0 cellSpacing=0
width=770>
<TBODY>
<TR bgColor=#006699>
<TD align=middle bgColor=#006699 id=white><FONT
color=#ffffff>对该文的评论</FONT></TD>
<TD align=middle>
<SCRIPT src="CSDN_文档中心_用 GDB 调试程序.files/readnum.htm"></SCRIPT>
</TD></TR></TBODY></TABLE>
<TABLE align=center bgColor=#666666 border=0 cellPadding=2 cellSpacing=1
width=770>
<TBODY>
<TR>
<TD bgColor=#cccccc colSpan=3><SPAN style="COLOR: #cccccc"><IMG height=16
hspace=1 src="CSDN_文档中心_用 GDB 调试程序.files/ico_pencil.gif" width=16>
</SPAN> jianjun_ding <I>(2000-10-24 16:04:09)</I>
</TD></TR>
<TR>
<TD bgColor=#ffffff colSpan=3 width=532><BR>又是抄袭!!!!
<BR></TD></TR></TBODY></TABLE><BR>
<DIV align=center>
<TABLE align=center bgColor=#cccccc border=0 cellPadding=2 cellSpacing=1
width=770>
<TBODY>
<TR>
<TH bgColor=#006699 id=white><FONT
color=#ffffff>我要评论</FONT></TH></TR></TBODY></TABLE></DIV>
<DIV align=center>
<TABLE border=0 width=770>
<TBODY>
<TR>
<TD>你没有登陆,无法发表评论。 请先<A
href="http://www.csdn.net/member/login.asp?from=/Develop/read_article.asp?id=534">登陆</A>
<A
href="http://www.csdn.net/expert/zc.asp">我要注册</A><BR></TD></TR></TBODY></TABLE></DIV><BR>
<HR noShade SIZE=1 width=770>
<TABLE border=0 cellPadding=0 cellSpacing=0 width=500>
<TBODY>
<TR align=middle>
<TD height=10 vAlign=bottom><A
href="http://www.csdn.net/intro/intro.asp?id=2">网站简介</A> - <A
href="http://www.csdn.net/intro/intro.asp?id=5">广告服务</A> - <A
href="http://www.csdn.net/map/map.shtm">网站地图</A> - <A
href="http://www.csdn.net/help/help.asp">帮助信息</A> - <A
href="http://www.csdn.net/intro/intro.asp?id=2">联系方式</A> - <A
href="http://www.csdn.net/english">English</A> </TD>
<TD align=middle rowSpan=3><A
href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><IMG
border=0 height=48 src="CSDN_文档中心_用 GDB 调试程序.files/biaoshi.gif"
width=40></A></TD></TR>
<TR align=middle>
<TD vAlign=top>百联美达美公司 版权所有 京ICP证020026号</TD></TR>
<TR align=middle>
<TD vAlign=top><FONT face=Verdana>Copyright © CSDN.net, Inc. All rights
reserved</FONT></TD></TR>
<TR>
<TD height=15></TD>
<TD></TD></TR></TBODY></TABLE></DIV>
<DIV></DIV><!--内容结束//--><!--结束//--></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -