我正在尝试在我的C代码中使用可变长度数组(VLA),并试图理解我们应该和不应该做什么。
我的功能有以下代码段:
void get_pdw_frame_usb(pdws_t *pdw_frame, pdw_io_t *pdw_io)
{
...
unsigned char buf[pdw_io->packet_size];
unsigned char *pdw_buf;
memset(buf, '\0', sizeof(buf));
pdw_io
是一个数据结构,其中包含packet_size
,其类型为size_t
char数组buf
用于存储usb批量传输数据包的内容
我正在尝试使用C99 VLA方法将其实例化为自动变量。我正在努力确保其内容全部为零。
我遇到了一些问题。
首先,如果将pdw_io->packet_size
设置为8(非常小),则将buf设置为合理的值,即使用gdb进行调试,我可以按如下方式检查:
(gdb) p buf
$27 = 0xbffe5be8 "\270", <incomplete sequence \370\267>
如果pdw_io->packet_size
设置为12008(相当大),那么我得到以下看起来不太好的内容:
(gdb) p buf
$29 = 0xbffe2d08 ""
VLA的12008个字符是否太大?或者也许那个gdb输出不用担心,它看起来有点像它没有给我分配任何东西?
同样在检查buf
的大小时,我在以下两种情况下都会得到以下结果:
(gdb) p sizeof(buf)
$30 = 0
我希望在第一个实例中为8,在第二个实例中为12008
我认为应该可以以这种方式使用sizeof
函数与VLA一起错误吗?
我的问题是随后的usb批量传输失败了,我想尝试排除它可能与我使用VLA有关的事实,这对我来说是一个新领域..
更新
写下以下最小,完整且有希望验证的程序,以尝试确认我的观察结果:
#include <stdio.h>
void test_vla(size_t n)
{
unsigned char buf[n];
printf("sizeof buf = %zu\n", sizeof buf);
}
int main()
{
test_vla(12008);
return 0;
}
现在如果我使用gdb打破printf
语句并运行p sizeof buf
我得到0但printf
输出12008.
gdb
版本是:
(gdb) show version
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
答案 0 :(得分:2)
您遇到的问题是gdb
中的错误(或者更确切地说是一个缺失的功能)。 gdb
无法正确处理应用于VLA(可变长度数组)的sizeof
运算符。
This message表示已在sizeof
中实施了对{0}的gdb
的支持,但仅在最近才实施。显然它不在你和我都使用的版本中(gdb 7.7.1)。如果没有这个修复,它会错误地将VLA的大小打印为0.您的代码本身应该正常运行;它只是gdb
没有正确处理它。
您的代码没有什么特别的错误,只要(a)它使用支持VLA的编译器编译,并且(b)数组的大小是正的而不是太大。 (C90中不支持VLA,除了可能作为扩展,在C99中作为标准功能引入,并且在C11中是可选的。)
可能的解决方法是修改程序,将sizeof vla
的值保存到一个变量中,然后可以从gdb
打印。
gdb
的另一个问题是打印VLA对象本身的行为与打印固定大小的数组对象的行为不同。它显然将VLA视为指向其第一个元素而不是数组对象的指针。
这里有gdb
成绩单,说明了问题:
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
[SNIP]
(gdb) list
1 #include <stdio.h>
2 #include <string.h>
3 int main(void) {
4 int len = 6;
5 char vla[len];
6 const size_t vla_size = sizeof vla;
7 char arr[6];
8 strcpy(vla, "hello");
9 strcpy(arr, "world");
10 }
(gdb) break 10
Breakpoint 1 at 0x400600: file c.c, line 10.
(gdb) run
Starting program: /home/kst/c
Breakpoint 1, main () at c.c:10
10 }
(gdb) print sizeof vla
$1 = 0
(gdb) print vla_size
$2 = 6
(gdb) print sizeof arr
$3 = 6
(gdb) print vla
$4 = 0x7fffffffdc10 "hello"
(gdb) print arr
$5 = "world"
(gdb) print arr+0
$6 = 0x7fffffffdc40 "world"
(gdb) continue
Continuing.
[Inferior 1 (process 28430) exited normally]
(gdb) quit
对于VLA来说,12008个字符是否太大?
可能不是。对于大多数实现,VLA可以与固定大小的阵列一样大。在:
之间没有真正的区别(就内存分配而言){
int size = 12008;
char buf[size];
}
和
{
int buf[12008];
}
许多系统限制了您可以在堆栈上分配的内存量,但是12008字节的阵列不可能推动这些限制。
尽管如此,如果您要分配大型数组,可能最好通过malloc()
这样做(这意味着您需要明确调用free()
对于每个已分配的对象)。