我正在尝试在我的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 ""

12008个字符对VLA来说是不是太大了?或者也许gdb输出不需要担心,它只是看起来有点像它没有分配给我什么?
另外,在检查buf的大小时,在这两种情况下,我都会得到以下结果:
(gdb) p sizeof(buf)
$30 = 0

我原以为第一次是8,第二次是1200
我是否错误地认为应该可以用这种方式在VLA中使用sizeof函数?
我的问题是随后的usb批量传输失败,我想尝试排除这可能与我使用VLAs有关的事实,这对我来说是一个新的领域。。
更新
编写了以下最小、完整且希望可验证的程序,以尝试确认我的观察结果:
#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

最佳答案

您遇到的问题是gdb中的一个bug(或者更准确地说是一个缺失的特性)。gdb无法正确处理应用于VLA(可变长度数组)的sizeof运算符。
来自gdb邮件列表的This message表明,对VLAs上的sizeof的支持已在gdb中实现,但只是最近才实现。显然,它不在你和我都在使用的版本中(gdb 7.7.1)。如果没有修复,它会错误地将VLA的大小打印为0。您的代码本身应该表现正确;只是gdb没有正确处理它。
您的代码没有什么特别的问题,只要(a)它是用支持VLAs的编译器编译的,并且(b)数组的大小是正的,并且不太大。(VLAs在C90中不受支持,可能作为扩展除外,在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

12008个字符对VLA来说是不是太大了?
可能不是。对于大多数实现,VLA可以和固定大小的数组一样大。在内存分配方面:
{
    int size = 12008;
    char buf[size];
}


{
    int buf[12008];
}

许多系统都会限制在堆栈上可以分配的内存量,但1200 8字节的数组不太可能达到这些限制。
不过,如果要分配大型数组,最好通过malloc()(这意味着您需要显式地为每个分配的对象调用free())。

关于c - C99可变长度数组的最大大小和sizeof函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32696800/

10-14 07:11