简体   繁体   English

C99可变长度数组的最大大小和sizeof函数

[英]C99 Variable Length Array Max sizes and sizeof Function

I am experimenting with the use of Variable Length Arrays (VLAs) in my C code and trying to iron out my understanding of what they should and shouldn't do. 我正在尝试在我的C代码中使用可变长度数组(VLA),并试图消除我对它们应该做什么和不应该做什么的理解。

I have the following snippet from my function: 我的功能中包含以下代码段:

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 is a data structure containing, amongst other things, packet_size , which is of type size_t pdw_io是一个数据结构,其中除其他外还包含packet_size ,其类型为size_t

the char array buf is to be used to store the contents of a usb bulk transfer packet char数组buf用于存储USB批量传输数据包的内容

I'm trying to instantiate it here as an automatic variable using the C99 VLA approach. 我正在尝试使用C99 VLA方法在此处将其实例化为自动变量。 I'm then trying to ensure its contents are all zeros. 然后,我试图确保其内容均为零。

I'm having a few issues. 我有几个问题。

Firstly, if pdw_io->packet_size is set to 8 (quite small), then buf is set to a reasonable looking value, ie debugging with gdb i can inspect it as follows: 首先,如果将pdw_io->packet_size设置为8(非常小),则buf设置为合理的值,即使用gdb进行调试时,我可以按以下方式对其进行检查:

(gdb) p buf
$27 = 0xbffe5be8 "\270", <incomplete sequence \370\267>

If pdw_io->packet_size is set to 12008 (fair bit larger), then I get the following which doesn't look so good: 如果将pdw_io->packet_size设置为12008( pdw_io->packet_size大一点),那么我得到的结果看起来不太好:

(gdb) p buf
$29 = 0xbffe2d08 ""

Is 12008 chars too large for a VLA? 12008字符对于VLA是否太大? Or perhaps that gdb output is not something to worry about, it just looks a bit like it hasn't allocated anything to me? 或者,也许不用担心gdb输出,它看起来好像还没有为我分配任何东西吗?

Also when inspecting the size of buf I get the following in both cases: 同样,在检查buf的大小时,在两种情况下我都会得到以下结果:

(gdb) p sizeof(buf)
$30 = 0

which I would have expected to be 8 in the 1st instance and 12008 in the 2nd 我本来希望一开始是8,而第二次是12008

Am I wrong in thinking it should be possible to use the sizeof function in this way with a VLA? 我是否认为应该可以在VLA中以这种方式使用sizeof函数,这是错误的吗?

My problem is that the subsequent usb bulk transfer is failing and I want to try and rule out the fact it may have something to do with my use of VLAs, which are a bit of a new area for me.. 我的问题是随后的USB批量传输失败,我想尝试排除它可能与我使用VLA有关的事实,这对我来说是一个新领域。

UPDATE UPDATE

Wrote the following minimal, complete and hopefully verifiable program to try and confirm my observations: 编写了以下最小,完整和可验证的程序,以尝试确认我的意见:

#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;
}

now if I break on the printf statement with gdb and run p sizeof buf I get 0 but printf outputs 12008. 现在,如果我用gdb中断了printf语句并运行p sizeof buf我将得到0,但printf输出12008。

gdb version is: gdb版本是:

(gdb) show version
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1

The problem you're running into is a bug (or perhaps more accurately a missing feature) in gdb . 您遇到的问题是gdb的错误(或更准确地说是缺少的功能)。 gdb does not correctly handle the sizeof operator applied to a VLA (variable-length array). gdb无法正确处理应用于VLA(可变长度数组)的sizeof运算符。

This message from a gdb mailing list indicates that support for sizeof on VLAs has been implemented in gdb , but only relatively recently. 来自gdb邮件列表的此消息表明,已在gdb实现了对VLA上sizeof支持,但只是最近才实现的。 Apparently it isn't in the version you and I are both using (gdb 7.7.1). 显然,您和我都没有使用的版本(gdb 7.7.1)。 Without that fix, it incorrectly prints the size of a VLA as 0. Your code itself should behave correctly; 如果没有该修补程序,它会将VLA的大小错误地打印为0。 it's just gdb that isn't handling it properly. 只是gdb无法正确处理它。

There's nothing particularly wrong with your code, as long as (a) it's compiled with a compiler that supports VLAs, and (b) the size of the array is positive and not too large. 只要(a)使用支持VLA的编译器进行编译,并且(b)数组的大小为正数且不会太大,则您的代码就没有什么特别的问题。 (VLAs are not supported in C90, except perhaps as an extension, were introduced as a standard feature in C99, and were made optional in C11.) (在C90中不支持VLA,除非作为扩展,在C99中作为标准功能引入了VLA,并在C11中将其作为可选功能。)

A possible workaround is to modify your program to save the value of sizeof vla to a variable that you can then print from gdb . 一个可能的解决方法是修改程序以将sizeof vla的值保存到一个变量,然后可以从gdb打印该变量。

Another problem with gdb is that printing the VLA object itself behaves differently than printing a fixed-size array object. gdb另一个问题是,打印VLA对象本身的行为与打印固定大小的数组对象不同。 It apparently treats a VLA as a pointer to its first element rather than as an array object. 显然,它将VLA视为指向其第一个元素的指针,而不是数组对象。

Here's a gdb transcript that illustrates the problem: 这是一个说明问题的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

Is 12008 chars too large for a VLA? 12008字符对于VLA是否太大?

Probably not. 可能不是。 For most implementations, a VLA can be just as large as a fixed-size array. 对于大多数实现,VLA可以与固定大小的数组一样大。 There's no real difference (in terms of memory allocation) between: 两者之间没有真正的区别(就内存分配而言):

{
    int size = 12008;
    char buf[size];
}

and

{
    int buf[12008];
}

Many systems limit the amount of memory you can allocate on the stack, but a 12008-byte array isn't likely to push those limits. 许多系统都会限制您可以在堆栈上分配的内存量,但是12008字节的数组不太可能达到这些限制。

Still, if you're going to be allocating large arrays, it's probably better to do so via malloc() (which means you'll need to explicitly call free() for each allocated object). 不过,如果您要分配大型数组,最好通过malloc()进行分配(这意味着您需要为每个分配的对象显式调用free() )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM