Gri*_*tov 3 c arrays sizeof c89 variable-length-array
我正在编写一段遗留代码(没有测试)。我偶然发现了隐藏在几个宏中的部分。如果使用 GCC 的-Wvla.
有问题的代码相当于在这个小程序中可以看到的代码:
\ntypedef struct entry {\n unsigned index;\n unsigned reserved;\n unsigned value;\n} entry_t;\n\nint main(int argc, char **argv) {\n long pa = 0;\n long res = pa + sizeof(entry_t[10 - argc]);\n return res;\n}\nRun Code Online (Sandbox Code Playgroud)\n编译时,会发出警告:
\n$ gcc -g -Wvla repro-vla.c\nrepro-vla.c: In function \xe2\x80\x98main\xe2\x80\x99:\nrepro-vla.c:9:5: warning: ISO C90 forbids variable length array [-Wvla]\n 9 | long res = pa + sizeof(entry_t[10 - argc]);\n | ^~~~\n\nRun Code Online (Sandbox Code Playgroud)\n罪魁祸首当然是这个表达式:sizeof(entry_t[10 - argc])。这里的语法有点混乱。我相信会创建一个用于10 - argc类型条目的临时匿名数组entry_t,然后获取其大小,然后丢弃该数组。
我的问题是:
\nsizeof(entry_t) * (10-argc)?两者计算相同的值,并且两者都没有采取任何措施来防止下溢(当 时argc >= 10)。第二个表达式不使用可变长度数组,因此不会生成警告,而且在我看来它也更容易理解。没有创建临时数组对象。
有一个常见的误解,认为 VLA 是关于在运行时定义长度的堆栈分配数组,这是一种更安全的形式alloca()。
不。VLA 是用于打字而不是存储。下面这行是“VLA-ness”的精髓:
typedef int T[n];
Run Code Online (Sandbox Code Playgroud)
不是:
int A[n];
Run Code Online (Sandbox Code Playgroud)
请注意,VLA 类型声明不分配任何存储空间,并且可以使用而不用担心堆栈溢出。VLA 类型对于处理多维数组和表达函数参数中的访问范围非常有用,即void foo(int n, int arr[n]);。VLA 类型在 C11 中是可选的,但由于其实用性,它们在 C23 中将是强制的。
该表达式sizeof(entry_t[10 - argc]本质上与以下相同:
typedef entry_t _unnamed_type[10 - argc];
sizeof(_unnamed_type)
Run Code Online (Sandbox Code Playgroud)
那里没有创建 VLA 数组对象。我认为问题在于-Wvla标志本身。它-Wvla警告任何VLA 类型(而不是 VLA 对象)的声明过于热心,因为它还捕获了 VLA 类型的良好用法。有人请求向 clang添加-Wvla-stack-allocation警告,以捕获 VLA 的危险用法。另一种方法是使用 gcc -Wvla-larger-than=0,但效果不太好。