【问题标题】:GDB C how to print VLA entries (dynamic array)GDB C如何打印VLA条目(动态数组)
【发布时间】:2019-12-17 10:23:41
【问题描述】:

我在stackoverflow上快速搜索后发布了这个......

我无法从 GDB 打印 VLA 条目,这是我的精简 C 片段。

#include <stdio.h>
#include <stdlib.h>

typedef struct  
{ int i, j; 
} c_t;

int f(int l, int c, c_t a[l][c])
{ for(int i=0;i<l;i++)
  { for(int j=0;j<c;j++)
    { a[i][j].i=i; a[i][j].j=j; 
    }
  }
}

int main(int ac, char **av)
{ int l=(int)atoi(av[1]), c=(int)atoi(av[2]);
  c_t a[l][c];
  return(f(l,c,a));
}

我编译它

$ cc -o g g.c -g -O0

然后在其上运行 GDB,在 f() 中进行几次迭代后,我尝试显示 a[i][j]

$ gdb  ./g
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
...[snip]...
Reading symbols from ./g...done.
(gdb) r 2 3
Breakpoint 1 at 0x76b: file g.c, line 17.

Breakpoint 1, main (ac=3, av=0x7fffffffe608) at g.c:17
17      { int l=(int)atoi(av[1]), c=(int)atoi(av[2]);
(gdb) n
18        c_t a[l][c];
(gdb) 
19        return(f(l,c,a));
(gdb) s
f (l=2, c=3, a=0x7fffffffe440) at g.c:8
8       int f(int l, int c, c_t a[l][c])
(gdb) n
9       { for(int i=0;i<l;i++)
(gdb) 
10        { for(int j=0;j<c;j++)
(gdb) 
11          { a[i][j].i=i; a[i][j].j=j; 
(gdb) 
10        { for(int j=0;j<c;j++)
(gdb) 
11          { a[i][j].i=i; a[i][j].j=j; 
(gdb) 
10        { for(int j=0;j<c;j++)
(gdb) 
11          { a[i][j].i=i; a[i][j].j=j; 
(gdb) 
10        { for(int j=0;j<c;j++)
(gdb) 
9       { for(int i=0;i<l;i++)
(gdb) p a[0][0]
Cannot perform pointer math on incomplete types, try casting to a known type, or void *.
(gdb) 

从那里我被卡住了,尝试了各种演员都没有成功。

提前感谢任何指针(可能是指针比数组更好:))

【问题讨论】:

  • 感谢大家的建议,我无法找到正确的转换语法。 @jxh,但是让我大吃一惊的是,如果您运行此测试程序,请在 f() 调用 init a[][] 上执行“n”(下一个),然后返回 main(),您现在可以执行 pa [0][0],那么为什么 p[0][0] 在 main() 中没有强制转换而不在 f() 中有效?

标签: c gdb dynamic-arrays variable-length-array


【解决方案1】:

当您从调试器打印a 时,您应该得到一个很大的提示:

...
Breakpoint 1, f (l=2, c=3, a=0x7fffffffe1b0) at x.c:8
8       int f(int l, int c, c_t a[l][c])
(gdb) p a
$1 = (c_t (*)[variable]) 0x7fffffffe1b0

调试器了解a 是指向c_t 的VLA 的指针,但假装不知道该数组的实际长度。但是,您知道它是3c 的值)。所以你可以简单地这样转换它。

(gdb) p c
$2 = 3
(gdb) p (c_t (*)[3])a
$3 = (c_t (*)[3]) 0x7fffffffe1b0
(gdb) p $3[0][0]
$4 = {i = -7552, j = 32767}

【讨论】:

    【解决方案2】:

    您可以检查变量的维度并创建一个指向已定义大小的数组的指针。当然,这不是最优的。但是这样你甚至可以看到整个数组:

    (gdb) p ((c_t (*)[3])a)[0][1]
    $30 = {i = 0, j = 1}
    (gdb) p ((c_t (*)[3])a)[1][1]
    $31 = {i = 1, j = 1}
    (gdb) p *((c_t (*)[2][3])a)
    $29 = {{{i = 0, j = 0}, {i = 0, j = 1}, {i = 0, j = 2}}, {{i = 1, j = 0}
    {i = 1, j = 1}, {i = 1, j = 2}}}
    

    【讨论】:

    • Thanx Antti,我喜欢打印 all 数组(小的时候)的想法。然而 GDB 似乎无法处理 $var,我会梦想将 $c = c 设置一次,然后 (gdb) p ((c_t (*)[$c])a)[1][1] =give= > 表达式中的语法错误,在 `$c])a)[1][1]' 附近。我猜GDB不是正交的:)
    【解决方案3】:

    应该一直有效的,实际上是指针运算。

    您可以使用类似以下命令:

    (gdb)  p *((c_t*)a+0*3+0)
    $3 = {i = 0, j = 0}
    (gdb)  p *((c_t*)a+0*3+1)
    $4 = {i = 0, j = 1}
    (gdb)  p *((c_t*)a+0*3+2)
    $5 = {i = 0, j = 2}
    (gdb)  p *((c_t*)a+1*3+0)
    $6 = {i = 1, j = 0}
    (gdb)  p *((c_t*)a+1*3+1)
    $7 = {i = 1, j = 1}
    (gdb)  p *((c_t*)a+1*3+2)
    $8 = {i = 1, j = 2}
    

    顺便说一句:与您的问题无关:f 的函数签名指定了 int 类型的返回值,但不返回任何内容。

    【讨论】:

    • 是的,什么都不返回意味着返回我猜想的最后一个 exp :) 我在点击 [send] 后看到了这个傻瓜,但它并没有改变问题的目的,所以我让它这样 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    相关资源
    最近更新 更多