1. 自动显示变量的值

使用 print 或者 p 命令来显示变量的值,但是有一个问题,即如果想要查看某个变量的值,需要不停地使用 print 命令。这对于需要观察那些不停变化的变量值来说,使用 p 命令就不太方便了,因为需要使用多次。

gdb 还有另外一个 display 命令,每次程序暂停都可以自动显示变量值。语法如下:

display 变量名

后面可以跟多个变量名,比如 display {var1,var2,var3}

我们使用 display 来自动观察 fun_test 中的变量 x ,而不是使用 print 命令,源码 demo.cpp 代码如下:

#include <iostream>
#include <string>void fun_test(int a, const char *str)
{printf("a is %d, str is %s\n", a, str);
}int main(int argc, char *argv[])
{for (int i = 0; i < 10; i++){fun_test(i, "test");}
}

调试过程如下:

(gdb) b fun_test
Breakpoint 1 at 0x799: file demo.cpp, line 6.
(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo Breakpoint 1, fun_test (a=0, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
(gdb) p a
$1 = 0
(gdb) p a
$2 = 0
(gdb) c
Continuing.
a is 0, str is testBreakpoint 1, fun_test (a=1, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
(gdb) p a
$3 = 1
(gdb) c
Continuing.
a is 1, str is testBreakpoint 1, fun_test (a=2, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
(gdb) p a
$4 = 2
(gdb) display a
1: a = 2
(gdb) c
Continuing.
a is 2, str is testBreakpoint 1, fun_test (a=3, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
1: a = 3
(gdb) c
Continuing.
a is 3, str is testBreakpoint 1, fun_test (a=4, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
1: a = 4
(gdb) c
Continuing.
a is 4, str is testBreakpoint 1, fun_test (a=5, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
1: a = 5
(gdb)

如果 display 命令后面跟多个变量名,则必须要求这些变量的类型相同(比如都是整型变量)。如果长度不相同,则需要分开使用。

可以在 gdb 中输入 info display 命令来查看已经设置的自动显示的变量信息,如图所示。

(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  a (cannot be evaluated in the current context)
(gdb)

如果不需要某些变量自动显示,则可以使用 undisplay 编号 的方式来取消自动变量的显示。例如,想要取消上面变量 a 的自动显示,则可以在 gdb 里面输入 undisplay 1 命令,a 变量的自动显示被取消,如图所示。这样一来,再次使用 info display 命令的时候不会显示 a 的信息。

(gdb) undisplay 1
(gdb) info display
There are no auto-display expressions now.
(gdb)

如果要取消所有变量的自动显示,可以使用 undisplay 命令来。在使用 undisplay 命令时会收到确认信息,确认是否全部取消自动显示。如果输入 y ,则取消所有的自动显示。delete display 命令也可以删除所有的自动显示。如果只想删除部分变量的自动显示,可以使用 delete display 序号 的方式。

比如要删除中的{x,a}的自动显示,则输入以下命令:

delete display 1

除了删除自动显示,还可以暂时禁用自动显示,在需要的时候可以再次启用某些变量的自动显示。比如图3-64中自动显示的编号 1 和 2,如果要暂时禁用编号为 1 的自动显示,则可以使用以下命令:

disable display 1

如果想要恢复编号为1的变量的自动显示,则可以使用以下命令来恢复:

enable display 1

2. 显示源代码

gdb 可以在调试的时候显示源代码信息。查看源代码的命令是 list 或者 l 。当程序命中断点或者暂停后可以使用 list 命令查看相关的源代码。

因为加上编译选项 -g 后,生成的可执行文件中包含调试信息,并且保存了对应的源文件信息(只是保存了源文件名等信息),所以在查看源代码时,要确保对应的源文件存在,否则无法查看。

在程序中断时,可以使用 l 命令来查看源代码信息。默认情况下,使用 l 命令可以显示10行源代码—当前代码行的前面 5 行和后面 5 行,

(gdb) c
Continuing.Breakpoint 1, fun_test (a=7, str=0x5555555548e9 "test") at demo.cpp:6
6       printf("a is %d, str is %s\n", a, str);
(gdb) l
1   #include <iostream>
2   #include <string>
3
4   void fun_test(int a, const char *str)
5   {6       printf("a is %d, str is %s\n", a, str);
7   }
8
9   int main(int argc, char *argv[])
10  {(gdb)

继续执行 l 命令,则会继续从当前行往后显示10行代码。如果执行 l- 命令,则会从当前代码行往前显示10行代码,

(gdb) l
11      for (int i = 0; i < 10; i++)
12      {13          fun_test(i, "test");
14      }
15  }
(gdb)

执行 l 命令时,每次默认显示 10 行代码,如果觉得每次显示的代码太少,可以通过 set listsize 命令来改变每次显示代码的行数。比如,希望每次能够显示 20 行代码,可执行下述命令:

set listsize 20

这样,每次调用 list 命令时,就会显示 20 行代码。

还可以使用 list 命令查看指定函数的代码,语法为 list 函数名 。比如,我们要查看 fun_test 函数的源代码,可以使用下述命令:

list fun_test

显示函数与显示普通代码的规则相同。

  • 受到行数的限制,比如我们刚设置了每次显示20行代码,则显示 fun_test 函数时只显示20行代码;
  • 仍然会以上下文的方式显示函数代码,即显示函数前面 10 行代码和函数后面 10 行代码;
(gdb) l fun_test
1   #include <iostream>
2   #include <string>
3
4   void fun_test(int a, const char *str)
5   {6       printf("a is %d, str is %s\n", a, str);
7   }
8
9   int main(int argc, char *argv[])
10  {(gdb)

如果想要查看指定文件的指定行代码,则可以使用下述命令:

list 文件名:行号

如果查看的是当前文件的代码行,则可以省略文件名。比如我们要查看 demo.cpp 的第 100 行代码,则可以使用下述命令进行查看:

l 100

示例过程

(gdb) l demo.cpp:9
4   void fun_test(int a, const char *str)
5   {6       printf("a is %d, str is %s\n", a, str);
7   }
8
9   int main(int argc, char *argv[])
10  {11      for (int i = 0; i < 10; i++)
12      {13          fun_test(i, "test");
(gdb) l 13
8
9   int main(int argc, char *argv[])
10  {11      for (int i = 0; i < 10; i++)
12      {13          fun_test(i, "test");
14      }
15  }
(gdb)

3. watch

watch 可以用来监视一个变量或者一段内存,当这个变量或者该内存处的值发生变化时,GDB 就会中断下来。被监视的某个变量或者某个内存地址会产生一个 watch point(观察点)。

适用场景:
有一个变量其值被意外地改掉了,通过单步调试或者挨个检查使用该变量的代码工作量会非常大,如何快速地定位到该变量在哪里被修改了?其实使用 watch 命令就可以通过添加硬件断点来达到监视数据变化的目的。

watch 命令的使用方式是 watch 变量名或内存地址 ,一般有以下几种形式:

  • 形式一:整型变量
int i;
watch i
  • 形式二:指针类型
char *p;
watch p 与 watch *p

注意:watch pwatch *p 是有区别的,前者是查看 *(&p),是 p 变量本身;后者是 p 所指内存的内容。我们需要查看地址,因为目的是要看某内存地址上的数据是怎样变化的。

  • 形式三:watch 一个数组或内存区间
char buf[128];
watch buf

这里是对 buf 的 128 个数据进行了监视,此时不是采用硬件断点,而是用软中断实现的。用软中断方式去检查内存变量是比较耗费 CPU 资源的,精确地指明地址是硬件中断。

注意:当设置的观察点是一个局部变量时,局部变量无效后,观察点也会失效。在观察点失效时 GDB 可能会提示如下信息:

Watchpoint 2 deleted because the program has left the block in which its expression is valid.

4. 查看内存

test_memory 函数内容
定义了字符串类型、int 变量和一个结构体,使用 gdb 启动调试,执行 b test_memory 命令为test_memory 函数设置一个断点,或者直接在 124 行设置一个断点。断点命中时,使用 x 命令查看各个变量的内存信息。x 命令的语法如下:

x /选项 地址

先查看字符串变量 str 的内存信息。执行 x str ,默认以十六进制显示。由于 str 是字符串,所以也可以使用字符串的方式查看。使用命令 x /s str 还可以以十进制方式查看、设定显示的宽度等,如图所示。
以十六进制方式查看时,显示的内存内容为0x74736574,对应的字符分别为t、s、e、t,即在内存中存储的内容刚好与我们看到的情况相反。如果以 x /s str 的方式查看,则会直接显示字符串的内容。

再来查看 int 型变量 number 在内存中的信息。因为 number 不是一个指针,所以我们要首先找到它的地址。可以使用 p &number 命令来查看 number 对应的地址,然后再使用 x 来查看 number 地址对应的内存数据。当然也可以直接使用 x &number 的方式来查看 number 地址对应的内存信息,如图所示。
在代码中,我们为 number 赋值为 0x12345678 ,但是内存中显示的却是 0x78563412 ,原因是字节在x86 架构中是按照小端方式存储的,第2章中已经介绍过。小端存储是指字节序数据的尾端数据存放在低地址部分,所以与我们看到的顺序刚好相反。

变量node存储的数据是一个结构体类型。来看看node在内存中到底是如何存储的。在gdb中输入命令x/16s node,如图3-73所示。
从图中可以看到,node在内存中的存储顺序与结构体中声明成员的顺序一致,即按照性别、ID和姓名来存储。显示性别的起始地址是0x614e70,显示ID的起始地址是0x614e74,“d”对应的是十进制的100。可以发现,ID的起始地址和性别的起始地址相差4,但是我们定义gender成员时使用的是char gender[3],明明只声明了3字节,最后却在内存中占用了4字节。

这是因为结构体在内存中会进行对齐和补齐操作,默认是按照4字节对齐。尽管声明的是3字节,但是要按照4字节去对齐,所以需要补齐1字节,这导致gender占用了4字节空间。同样,成员Name也会补齐到8字节,所以整个结构体在内存中会占用16字节,可以使用p sizeof(TEST_NODE)命令进行查看。在图3-73中也可以发现,整个结构体的大小是16字节。

命令x并不局限于查看变量的内存信息,无论是函数地址、变量地址,还是其他地址,只要地址合法而且可以访问,都可以使用 x 命令来查看。

gdb 笔记(07)— 自动显示变量值、显示源代码、监视变量或内存、查看内存相关推荐

  1. 基于STM32的0.96OLED基本显示学习,及 上下或左右的滑动显示长字符(使用硬件刷屏模式),OLED显示变量值操作详细解析

    基于STM32的0.96OLED基本显示学习,及 上下或左右的滑动显示长字符(使用硬件刷屏模式),OLED显示变量值操作详细解析 简   介 一.项目说明 二.学习入门 1)开始了解例程 三.实战过程 ...

  2. python显示变量值_Python 中如何打印变量值

    展开全部 python打印变量的值需32313133353236313431303231363533e78988e69d8331333366306435要用到print语句,具体的使用方法如下: 1. ...

  3. 竖排显示变横排显示的方法

    以上是VC的属性页,怎么设计使得竖排显示变成横排显示啊??? 感觉这两个界面不是一样的,不能这样的问,所以本问题取消.

  4. 《JavaScript高级程序设计(第四版)》红宝书学习笔记(2)(第四章:变量、作用域与内存)

    个人对第四版红宝书的学习笔记.不适合小白阅读.这是part2.持续更新,其他章节笔记看我主页. (记 * 的表示是ES6新增的知识点,记 ` 表示包含新知识点) 第四章:变量.作用域与内存 4.1 原 ...

  5. jsp当前页的变量值显示到文本框中hint_Word中常用的这9个打印技巧,你不一定全懂,非常实用...

    在工作中,经常需要打印各种文档,看似很简单的操作,如果使用不当,也是很麻烦的事儿,不要说浪费纸张,还有可能打印不出你想要的结果. 今天,我们就来分享一下word2016中的9个实用打印技巧,一定能帮到 ...

  6. java中label数值_java – 如何在JLabel中显示变量值

    我是 Java编程的新手.我想在输出窗口中显示我的变量的值,而不是在控制台视图中. 代码如下: import java.awt.BorderLayout; import javax.swing.JFr ...

  7. ECLIPSE 调试模式无法显示 变量值

    网上搜索了一下,方法集中在两种: 1.  Window->Preferences->Java->Editor->Hovers 将[Variable Values]选择即可,如果 ...

  8. mysql 存储过程 用户变量值_mysql:用户变量、系统变量、局部变量(存储过程中的)...

    MySQL数据库中的变量分为MySQL系统变量和MySQL用户变量. 一.MySQL用户变量:基于会话变量实现的, 可以暂存值, 并传递给同一连接里的下一条sql使用的变量.当客户端连接退出时,变量会 ...

  9. IAR中如何实时观察变量值

    用一个简单的程序演示一下,首先进入到调试界面. 选中要观察的变量,然后单击鼠标右键选择 Add to Watch "j",将要观察的变量依次添加到观察窗口,然后单步执行,或者让程序 ...

最新文章

  1. poj3096(set的应用)
  2. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(自定义分组的次序)实战
  3. 李茶:虎牙直播推荐系统架构详解
  4. 社交网络图挖掘1--将社交网络看作图及其聚类
  5. js中!和!!的区别及用法
  6. MFC类结构-1、CObject类
  7. 一个比较简单驱动程序初学者可以看看
  8. 小白学数据分析-----ARPDAU的价值
  9. C++读写文件总结 .
  10. 华为机试HJ23:删除字符串中出现次数最少的字符
  11. iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄...
  12. Windows XP Embedded下载
  13. 三维空间坐标的旋转算法详解_任意旋转角三维空间直角坐标转换的迭代算法
  14. 如何利用eclipse创建一个java web项目?
  15. HackTheBox - Unified
  16. 13-TCP 协议(FIN_WAIT2)
  17. npm查看一个包的版本信息
  18. python计算机视觉学习第三章——图像到图像的映射
  19. uber优步提高成单率,轻松拿奖励!
  20. 发光二极管的keil代码c语言,用Keil点亮一个发光二极管

热门文章

  1. java开发 Ultraedit_Java开发工具配置 UltraEdit
  2. matlab最小二乘 弹性网络,基于弹性SCAD罚函数的回声状态网络时间序列预测方法与流程...
  3. class path resource [spring/] cannot be resolved to URL because it does not exist问题解决(IDEA)
  4. 使用OpenXml转换docx内容为RTF
  5. angular :ngIf 的else用法
  6. 【PaperReading】OpenHGNN:An Open-Source Toolkit for Heterogeneous Graph Neural Networks
  7. 大专出身,28K上岸B站测开岗,光一面就花了我8个小时···
  8. 计算机存储器的种类有哪些,计算机存储器的种类和特点
  9. 渗透测试完整流程(未完待续)
  10. java 使用fusioncharts_FusionCharts使用教程:自定义图表——画布