2. 查看变量与内存内容

任务目标

使用GDB的print和x命令,在程序运行时查看变量当前值、变量地址以及指定内存区域的内容,从而观察数据在程序执行过程中的变化。

环境与依赖

  • Linux环境,安装gcc和gdb
  • 编译时添加-g选项保留调试符号

示例程序

创建文件var_demo.c,内容如下:

#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[16];
    float score;
} Student;

int main() {
    int count = 3;
    int arr[4] = {10, 20, 30, 40};
    char msg[] = "GDB-Demo";
    Student stu = {1001, "Tom", 88.5f};

    printf("count=%d, arr[0]=%d, msg=%s, stu.id=%d\n",
           count, arr[0], msg, stu.id);

    // 修改数据,便于观察变化
    count = 5;
    arr[2] = 99;
    strcpy(msg, "Changed");
    stu.score = 95.0f;

    printf("After modification: count=%d, arr[2]=%d, msg=%s, stu.score=%.1f\n",
           count, arr[2], msg, stu.score);

    return 0;
}

编译:

gcc -g -o var_demo var_demo.c

GDB调试步骤

启动GDB并设置断点:

gdb ./var_demo
(gdb) break var_demo.c:15
(gdb) run

程序在第一个printf处暂停,此时执行以下命令查看变量:

(gdb) print count
$1 = 3
(gdb) print arr
$2 = {10, 20, 30, 40}
(gdb) print arr[2]
$3 = 30
(gdb) print msg
$4 = "GDB-Demo"
(gdb) print stu
$5 = {id = 1001, name = "Tom", score = 88.5}
(gdb) print &count
$6 = (int *) 0x7fffffffe1ac
(gdb) print &stu
$7 = (Student *) 0x7fffffffe190

使用x命令查看内存内容(地址以上述输出为准,实际地址可能不同):

(gdb) x/4dw &arr
0x7fffffffe190: 10    20    30    40
(gdb) x/8cb msg
0x7fffffffe1b0: 71 'G'  68 'D'  66 'B'  45 '-'  68 'D'  101 'e'  109 'm'  111 'o'
(gdb) x/3uw &stu
0x7fffffffe1c0: 1001  1818581860  1120403456

说明:x/4dw表示以4个十进制有符号字(4字节为单位)显示;x/8cb表示以8个单字节字符形式显示;x/3uw表示以3个无符号字显示。结构体stu的内存中,name字段的ASCII码值("Tom")以十六进制显示为0x54 0x6f 0x6d,对应十进制84 111 109,与1818581860的字节序相关(小端存储)。

继续执行到第二个断点:

(gdb) continue
(gdb) break var_demo.c:22
(gdb) continue

此时再次查看变量,观察变化:

(gdb) print count
$8 = 5
(gdb) print arr[2]
$9 = 99
(gdb) print msg
$10 = "Changed"
(gdb) print stu.score
$11 = 95

验证方法与判定标准

  • 在第一个断点处,print输出的变量值与源码中初始化值一致:count=3、arr[2]=30、msg="GDB-Demo"、stu.id=1001。
  • x命令显示的内存内容与print得到的变量值一致(注意字节序和数据类型宽度)。
  • 执行到第二个断点后,print显示的值与修改后的赋值一致:count=5、arr[2]=99、msg="Changed"、stu.score=95。
  • 通过print &变量名能获得变量地址,且该地址与x命令使用的地址一致。

常见问题

  • 地址每次运行不同:ASLR(地址空间布局随机化)导致每次运行时栈地址变化,但GDB中print &var给出的地址始终是当前进程的有效地址,直接使用即可。
  • x命令格式:x/nfu addr中n是重复次数,f是显示格式(d十进制、x十六进制、c字符、s字符串、f浮点),u是单位大小(b单字节、h双字节、w四字节、g八字节)。
  • 结构体内存布局:由于对齐,结构体字段之间可能有填充字节,直接查看原始内存时可能看到非直观数值,建议结合print命令确认字段值。