1

C 函数回溯只返回程序的一系列函数调用,但我想列出程序中的所有局部变量,就像 gdb 中的信息局部变量一样。知道这是否可以做到吗?谢谢

4

3 回答 3

3

一般来说,没有。您应该摆脱将“堆栈”视为某种上帝给定的事实的想法。调用堆栈只是 C 的一种常见实现技术。它没有内在含义或必需的语义。自动变量(如您所说的“局部变量”)必须以某种方式运行,有时这意味着它们被写入调用堆栈。但是,完全可以想象,局部变量根本不会在内存中实现——它们可能只会存储在处理器寄存器中,或者如果可以在没有它们的情况下制定等效程序,则完全消除它们。

所以,不,没有用于枚举局部变量的语言内在机制。正如您所说,调试器可以在某种程度上这样做(取决于存在的调试符号并进行优化);也许您可以找到一个可以从正在运行的程序中处理调试符号的库。

于 2012-08-27T14:21:04.920 回答
0

如果这只是为了偶尔调试,那么您可以调用调试器。但是,由于调试器本身会冻结您的程序,因此您需要一个中介来捕获输出。例如,您可以使用system并将输出重定向到文件,然后再读取该文件。在下面的示例中,该文件gdbcmds.txt包含行info locals.

char buf[512];
FILE *gdb;
snprintf(buf, sizeof(buf), "gdb -batch -x gdbcmds.txt -p %d > gdbout.txt",
         (int)getpid());
system(buf);
gdb = fopen("gdbout.txt", "r");
while (fgets(buf, sizeof(buf), gdb) != 0) {
    printf("%s", buf);
}
fclose(gdb);
于 2012-08-27T14:39:51.607 回答
0

首先,请注意它backtrace不是标准的 C 库函数,而是 GNU 特定的扩展。

一般来说,很难从编译后的代码中检索局部变量信息,特别是如果它是在没有调试或启用优化的情况下编译的。如果未打开调试,变量名称和类型通常不会保留在生成的机器代码中。

例如,使用以下简单得离谱的代码:

#include <stdio.h>
#include <math.h>

int main(void)
{
  int x = 1, y = 2, z;
  z = 2 * y - x;
  printf("x = %d, y = %d, z = %d\n", x, y, z);
  return 0;
}

这是生成的机器代码,没有调试或优化:

        .file   "varinfo.c"
        .version        "01.01"
gcc2_compiled.:
                .section        .rodata
.LC0:
        .string "x = %d, y = %d, z = %d\n"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    $1, -4(%ebp)
        movl    $2, -8(%ebp)
        movl    -8(%ebp), %eax
        movl    %eax, %eax
        sall    $1, %eax
        subl    -4(%ebp), %eax
        movl    %eax, -12(%ebp)
        pushl   -12(%ebp)
        pushl   -8(%ebp)
        pushl   -4(%ebp)
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        movl    $0, %eax
        leave
        ret
.Lfe1:
        .size    main,.Lfe1-main
        .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"

xy和分别通过、和z引用。除了用于执行算术的指令外,没有任何迹象表明它们是整数。 -4(%ebp)-8(%ebp)-12(%ebp)

打开优化(-O1)会更好:

        .file   "varinfo.c"
        .version        "01.01"
gcc2_compiled.:
        .section        .rodata.str1.1,"ams",@progbits,1
.LC0:
        .string "x = %d, y = %d, z = %d\n"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        pushl   $3
        pushl   $2
        pushl   $1
        pushl   $.LC0
        call    printf
        movl    $0, %eax
        leave
        ret
.Lfe1:
        .size    main,.Lfe1-main
        .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"

在这种情况下,编译器能够进行一些静态分析并z在编译时计算值;根本不需要为任何变量留出任何内存,因为编译器已经知道这些值必须是什么。

于 2012-08-27T15:33:43.047 回答