LV081-gdb-print
一、print
1. 语法格式
print 命令,它的功能就是在 GDB 调试程序的过程中,输出或者修改指定变量或者表达式的值。
Tips:所谓表达式,简单理解就是由多个变量构成的式子。例如 a、b、c 为单个变量,a+b、a+b*c 即为表达式。
print 命令可以缩写为 p,最常用的语法格式如下所示:
# 输出 val 的值
(gdb) print val
(gdb) p val
# 修改 val的值为num
(gdb) print val=num
(gdb) p val=num其中,参数 val 用来代指要查看或者修改的目标变量或者表达式。
2. 其他用法
print 命令还有更高级的功能和用法,例如以指定的格式输出变量或者表达式的值、输出数组中指定区间内的所有元素等等。和 print 命令最基本的用法相比,该命令的完整语法格式如下所示:
(gdb) print [options --] [/fmt] expr格式中用 [ ] 括起来的部分是可选的,可以使用也可以省略。
其中,各个参数的含义如下:
options:表示该命令所支持的选项,这些选项可以控制 print 命令输出指定内容的变量或者表达式的值;
fmt:指定输出变量或表达式值时所采用的格式;
expr:指定要查看的变量或表达式。
2.1 options
表 1 列举了常用的几个 options 参数值。
| options 参数 | 功 能 |
|---|---|
| -address on|off | 查看某一指针变量的值时,是否同时打印其占用的内存地址,默认值为 on。该选项等同于单独执行 set print address on|off 命令。 |
| -array on|off | 是否以便于阅读的格式输出数组中的元素,默认值为 off。该选项等同于单独执行 set printf array on|off 命令。 |
| -array-indexes on|off | 对于非字符类型数组,在打印数组中每个元素值的同时,是否同时显示每个元素对应的数组下标,默认值为 off。该选项等同于单独执行 set print array-indexes on|off 命令。 |
| -pretty on|off | 以便于阅读的格式打印某个结构体变量的值,默认值为 off。该选项等同于单独执行 set print pretty on|off 命令。 |
注意,options 参数和 /fmt 或者 expr 之间,必须用 --( 2 个 - 字符)分隔。此外,options 参数还有很多选项可以使用,可以 GDB 官网 查看。
2.2 fmt
print 命令可允许自定义输出格式,表 2 罗列了几个常用的 /fmt 参数:
| /fmt | 功 能 |
|---|---|
| /x | 以十六进制的形式打印出整数。 |
| /d | 以有符号、十进制的形式打印出整数。 |
| /u | 以无符号、十进制的形式打印出整数。 |
| /o | 以八进制的形式打印出整数。 |
| /t | 以二进制的形式打印出整数。 |
| /f | 以浮点数的形式打印变量或表达式的值。 |
| /c | 以字符形式打印变量或表达式的值。 |
当 print 命令不指定任何 options 参数时,print 和 /fmt 之间不用添加空格,例如以十六进制的形式输出 num 整形变量的值,执行命令为 (gdb) print/x num。
2.3 目标是表达式
当print指定目标表达式时,除了表达式本身外,GDB 调试器还支持使用@和::运算符。
2.3.1 @
@运算符用于输出数组中指定区域的元素,使用格式如下:
(gdb) print first@len其中,参数 first 用于指定数组查看区域内的首个元素的值;参数 len 用于指令自 first 元素开始查看的元素个数。假设有一个 array 数组,其定义如下:
int array[5] = {1,2,3,4};如果我们想查看第 1 个元素和第 2 个元素的值,可以执行如下指令:
(gdb) print array[0]@2
$1 = {1, 2}2.3.2 ::
当程序中包含多个作用域不同但名称相同的变量或表达式时,可以借助::运算符明确指定要查看的目标变量或表达式。::运算符的语法格式如下:
(gdb) print file::variable
(gdb) print function::variable其中 file 用于指定具体的文件名,funciton 用于指定具体所在函数的函数名,variable 表示要查看的目标变量或表达式。举个例子:
#include <stdio.h>
int num = 10;
int main()
{
int num = 20;
return 0;
}假设该程序存储在 main.c 文件中,则使用 GDB 调试至第 5 行(return 0)处暂停后,通过执行如下命令,即可查看 num 全局变量的值:
(gdb) print 'main.c'::num
$1 = 10而通过执行如下命令,可以查看 num 局部变量的值:
(gdb) p main::num
$1 = 20当然,由于 GDB 调试就暂停在 main() 函数中,因此即便不指明main::,这里的 num 默认指代的也是 num 局部变量。
二、使用示例
1. 基础用法
1.1 测试程序
#include <stdio.h>
int main(int argc, const char *argv[]) {
int num, result = 0, i = 0;
scanf("%d", &num);
while (i <= num) {
result += i;
i++;
}
printf("result = %d\n", result);
return 0;
}我们在ubuntu中测试,所以直接用下面的命令编译:
cd ~/workspace/c-learning/02-c-basic/21-debug
gcc 033-gdb-print-basic.c -g1.2 调试示例
✓ sumu@virtual-machine:~/workspace/c-learning/02-c-basic/21-debug [main ≡ +1 ~0 -0 !]
$ gdb a.out -q
Reading symbols from a.out...
(gdb) l # <=== 1. 查看源码
1 #include <stdio.h>
2 int main(int argc, const char *argv[]) {
3 int num, result = 0, i = 0;
4 scanf("%d", &num);
5 while (i <= num) {
6 result += i;
7 i++;
8 }
9 printf("result = %d\n", result);
10 return 0;
(gdb) b 3 # <=== 2. 在第3行打断点
Breakpoint 1 at 0x11ab: file 034-gdb-display.c, line 3.
(gdb) r # <=== 3. 运行程序到断点处暂停
Starting program: /home/sumu/workspace/c-learning/02-c-basic/21-debug/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffce28) at 034-gdb-display.c:3
3 int num, result = 0, i = 0;
(gdb) n # <=== 4. 继续执行1行
4 scanf("%d", &num);
(gdb) n # <=== 5. 再执行1行
3 # <=== 6. 输入num的值为3
5 while (i <= num) {
(gdb) p num # <=== 7. 打印num的值
$1 = 3
(gdb) p num=4 # <=== 8. 设置num的值为4
$2 = 4
(gdb) b 9 # <=== 9. 在第9行添加断点
Breakpoint 2 at 0x5555555551e5: file 034-gdb-display.c, line 9.
(gdb) c # <=== 10. 继续运行
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffce28) at 034-gdb-display.c:9
9 printf("result = %d\n", result);
(gdb) p result # <=== 11. 打印出result的值
$3 = 10
(gdb) p result=20 # <=== 12. 修改 result 的值为20
$4 = 20
(gdb) c
Continuing.
result = 20 # <=== 13. 最终result的值为前面设置的20
[Inferior 1 (process 23956) exited normally]
(gdb)2. 其他用法
2.1 测试程序
#include <stdio.h>
struct student {
int id;
char *name;
int age;
};
int num = 20;
int main(int argc, const char *argv[]) {
int i = 1;
int num = 10;
int arr[10] = {0, 1, 2, 3, 4, 5};
struct student stu = {1001, "sumu", 20};
printf("num = %d\n", num);
for (i = 0; i < 10; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
printf("Student ID: %d\n", stu.id);
printf("Student Name: %s\n", stu.name);
printf("Student Age: %d\n", stu.age);
return 0;
}我们在ubuntu中测试,所以直接用下面的命令编译:
cd ~/workspace/c-learning/02-c-basic/21-debug
gcc 034-gdb-print-advanced -g2.2 调试示例
✓ sumu@virtual-machine:~/workspace/c-learning/02-c-basic/21-debug [main ≡ +1 ~0 -0 !]
$ gdb a.out -q
Reading symbols from a.out...
(gdb) l # <=== 1. 查看源码
warning: Source file is more recent than executable.
1 #include <stdio.h>
2 struct student {
3 int id;
4 char *name;
5 int age;
6 };
7 int num = 20;
8 int main(int argc, const char *argv[]) {
9 int i = 1;
10 int num = 10;
(gdb)
11 int arr[10] = {0, 1, 2, 3, 4, 5};
12 struct student stu = {1001, "sumu", 20};
13
14 printf("num = %d\n", num);
15 for (i = 0; i < 10; i++) {
16 printf("arr[%d] = %d\n", i, arr[i]);
17 }
18 printf("Student ID: %d\n", stu.id);
19 printf("Student Name: %s\n", stu.name);
20 printf("Student Age: %d\n", stu.age);
(gdb)
21 return 0;
22 }
(gdb) b 14 # <=== 2. 在第14行打断点
Breakpoint 1 at 0x11fd: file 033-gdb-print.c, line 14.
(gdb) r # <=== 3. 运行程序并暂停
Starting program: /home/sumu/workspace/c-learning/02-c-basic/21-debug/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffce28) at 033-gdb-print.c:14
14 printf("num = %d\n", num);
(gdb) print -address on -- stu.name # <=== 4. 打印指针的同时,输出指针所在的内存地址
$1 = 0x555555556004 "sumu"
(gdb) print -address off -- stu.name # <=== 5. 打印指针,不输出所在地址
$2 = "sumu"
(gdb) print -pretty on -- stu # <=== 6. 以便于阅读的方式输出结构体的值
$3 = {
id = 1001,
name = 0x555555556004 "sumu",
age = 20
}
(gdb) print stu # <=== 7. 压缩格式输出结构体的值
$4 = {id = 1001, name = 0x555555556004 "sumu", age = 20}
(gdb) print/x num # <=== 8. 十六进制格式打印num的值
$5 = 0xa
(gdb) print arr[1]@5 # <=== 9. 从arr[1]处,输出数组后面5个元素的值
$6 = {1, 2, 3, 4, 5}
(gdb) print num # <=== 10.输出局部变量num的值
$7 = 10
(gdb) print '033-gdb-print.c'::num # <=== 11. 输出全局变量num的值
$8 = 20
(gdb)