《软件调试的艺术》笔记--检查和设置变量

2024-04-14 21:48

本文主要是介绍《软件调试的艺术》笔记--检查和设置变量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.使用print命令查看变量值

使用print命令(简写为p)可以查看变量值。

使用如下的程序1进行测试。

#include <stdio.h>struct node{int index;struct node* next;
};int main(void) {struct node head;head.index = 1;head.next = NULL;int i;for(i=0; i<3; i++){head.index++;}return 0;
}
(gdb) b main
Breakpoint 1 at 0x804839a: file a.c, line 10.
(gdb) r
Starting program: /root/a.out

Breakpoint 1, main () at a.c:10
10              head.index = 1;
(gdb) n
11              head.next = NULL;
(gdb)
14              for(i=0; i<3; i++){
(gdb)
15                      head.index++;
(gdb)
14              for(i=0; i<3; i++){
(gdb) p head
$1 = {index = 2, next = 0x0}
(gdb) n
15                      head.index++;
(gdb)
14              for(i=0; i<3; i++){
(gdb)
15                      head.index++;
(gdb)
14              for(i=0; i<3; i++){
(gdb) p head
$3 = {index = 4, next = 0x0}


print命令允许指定可选的格式,例如

p/x y

会以十六进制格式显示变量,而不是十进制。其他常用的格式为c(字符),s(字符串),f(浮点型)


2.使用display命令查看变量值

每次遇到断点,只需要键入print命令就能够查看变量值,但是,如果知道会在每次遇到断点时键入这个命令,那么使用
display命令(简写为disp)能节省更多的时间。这个命令要求GDB在执行每次有暂停时就输出指定条目。
使用上面的程序1输出的调试的结果如下:
(gdb) b main
Breakpoint 1 at 0x804839a: file a.c, line 10.
(gdb) b 15
Breakpoint 2 at 0x80483b1: file a.c, line 15.
(gdb) r
Starting program: /root/a.out


Breakpoint 1, main () at a.c:10
10              head.index = 1;
(gdb) disp head
1: head = {index = -1208168460, next = 0x80483d0}
(gdb) c
Continuing.


Breakpoint 2, main () at a.c:15
15                      head.index++;
1: head = {index = 1, next = 0x0}
(gdb)
Continuing.


Breakpoint 2, main () at a.c:15
15                      head.index++;
1: head = {index = 2, next = 0x0}
(gdb)
Continuing.


Breakpoint 2, main () at a.c:15
15                      head.index++;
1: head = {index = 3, next = 0x0}
(gdb)
可以临时禁用某个显示项,例如:
dis disp 1
临时禁用显示列表中的条目1,条目可以通过 info disp命令检查。
要重新启用条目,使用enable
enable disp 1
要完全删除条目,使用undisplay(简写为undisp)
undisp 1

3.使用call命令调用函数

使用call函数可以调用被调试程序的函数。
使用下面的程序2进行演示:
#include <stdio.h>struct node{int index;char* content;struct node* next;
};void display(struct node head){printf("head.index=%d,head.content=%s\n",head.index,head.content);
}int main(void) {struct node head;head.index = 1;head.content = "yes";head.next = NULL;int i;for(i=0; i<3; i++){head.index++;}display(head);return 0;
}

(gdb) b main
Breakpoint 1 at 0x80483f0: file a.c, line 15.
(gdb) r
Starting program: /root/a.out

Breakpoint 1, main () at a.c:15
15              head.index = 1;
(gdb) n
16              head.content = "yes";
(gdb)
17              head.next = NULL;
(gdb)
20              for(i=0; i<3; i++){
(gdb)
21                      head.index++;
(gdb) call display(head)
head.index=1,head.content=yes

4.使用ptype查看变量类型

使用程序2进行调试:
(gdb) b main
Breakpoint 1 at 0x804842a: file a.c, line 16.
(gdb) r
Starting program: /root/a.out

Breakpoint 1, main () at a.c:16
16              head.index = 1;
(gdb) ptype head
type = struct node {
    int index;
    char *content;
    struct node *next;
}
(gdb)

5.监视局部变量

使用info locals命令得到当前栈帧中所有局部变量的值列表。
使用程序2进行调试:
(gdb) b main
Breakpoint 1 at 0x804842a: file a.c, line 16.
(gdb) r
Starting program: /root/a.out

Breakpoint 1, main () at a.c:16
16              head.index = 1;
(gdb) info locals
head = {index = -1209402059,
  content = 0xb7ff0a50 "U\211\345WV1\366S\350N\212", next = 0x804849b}
i = -1208168460
(gdb) n
17              head.content = "yes";
(gdb)
18              head.next = NULL;
(gdb)
21              for(i=0; i<3; i++){
(gdb) info locals
head = {index = 1, content = 0x8048574 "yes", next = 0x0}
i = -1208168460
(gdb) n
22                      head.index++;
(gdb) info local
head = {index = 1, content = 0x8048574 "yes", next = 0x0}
i = 0
(gdb)

6.检查动态数组

对下面的程序3进行调试。
#include <stdio.h>
#include <malloc.h>int main(void){int a[3] = {1,2,3};int *b = (int*)malloc(3*sizeof(int));b[0] = 1;b[1] = 2;b[2] = 3;return 0;
}

(gdb) b main
Breakpoint 1 at 0x80483cd: file b.c, line 5.
(gdb) r
Starting program: /root/a.out

Breakpoint 1, main () at b.c:5
5               int a[3] = {1,2,3};
(gdb) n
6               int *b = (int*)malloc(3*sizeof(int));
(gdb)
7               b[0] = 1;
(gdb)
8               b[1] = 2;
(gdb)
9               b[2] = 3;
(gdb)
10              return 0;
(gdb) p a
$1 = {1, 2, 3}
(gdb) p b
$2 = (int *) 0x804b008
(gdb) p *b
$3 = 1

如果是动态数组,直接使用p命令只能打印一个数。
使用如下命令,可以打印出整个数组:
(gdb) p *b@3
$1 = {1, 2, 3}
(gdb) 

语法如下:
p *pointer@number_of_elements.

另一种方式是使用类型强制转换:
(gdb) p (int [3])*b
$3 = {1, 2, 3}
(gdb)

7.设置变量

在gdb中,值的设置非常容易,例如
set x=12
会将x的当前值修改为12.

可以通过gdb的set args命令设置程序的命令行参数,该命令可以需要下次执行run命令时才会发生变化。其实只要在调用
gdb的run命令时使用新参数就能达到同样的效果。

gdb提供info args命令来检查当前函数的参数。

使用下面的程序4进行调试:
#include <stdio.h>void display(int i, char* argv)
{printf("argv[%d]=%s\n",i,argv);
}int main(int argc, char* argv[])
{int i;for (i=0; i<argc; i++) {display(i,argv[i]);}return 0;
}
调试:
(gdb) set args 1 2 3
(gdb) b main
Breakpoint 2 at 0x80483f0: file a.c, line 11.
(gdb) b display
Note: breakpoint 1 also set at pc 0x80483ca.
Breakpoint 3 at 0x80483ca: file a.c, line 5.
(gdb) r
Starting program: /root/a.out 1 2 3

Breakpoint 2, main (argc=4, argv=0xbffff724) at a.c:11
11              for (i=0; i<argc; i++) {
(gdb) info args
argc = 4
argv = 0xbffff724
(gdb) c
Continuing.

Breakpoint 1, display (i=0, argv=0xbffff86a "/root/a.out") at a.c:5
5               printf("argv[%d]=%s\n",i,argv);
(gdb) c
Continuing.
argv[0]=/root/a.out

Breakpoint 1, display (i=1, argv=0xbffff876 "1") at a.c:5
5               printf("argv[%d]=%s\n",i,argv);
(gdb)
Continuing.
argv[1]=1

Breakpoint 1, display (i=2, argv=0xbffff878 "2") at a.c:5
5               printf("argv[%d]=%s\n",i,argv);
(gdb)
Continuing.
argv[2]=2

Breakpoint 1, display (i=3, argv=0xbffff87a "3") at a.c:5
5               printf("argv[%d]=%s\n",i,argv);
(gdb)
Continuing.
argv[3]=3

这篇关于《软件调试的艺术》笔记--检查和设置变量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/904110

相关文章

变量与命名

引言         在前两个课时中,我们已经了解了 Python 程序的基本结构,学习了如何正确地使用缩进来组织代码,并且知道了注释的重要性。现在我们将进一步深入到 Python 编程的核心——变量与命名。变量是我们存储数据的主要方式,而合理的命名则有助于提高代码的可读性和可维护性。 变量的概念与使用         在 Python 中,变量是一种用来存储数据值的标识符。创建变量很简单,

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2