变量data是一个variable length array,声明为函数参数时不一定需要有一个整数常量大小:
如果表达式不是整数常量表达式,则声明符用于可变大小的数组。
实际上,大小在函数原型范围内被隐式忽略:
如果大小为 *,则声明用于未指定大小的 VLA。这样的声明只能出现在函数原型范围内,并且声明了一个完整类型的数组。事实上,函数原型范围内的所有 VLA 声明符都被视为表达式被替换为 *。
(“表达式”通常在方括号之间并指定大小。)
换句话说,在函数原型中,根本不需要知道大小,仍然认为类型是完整的。只有在函数定义中才需要将大小指定为一些非常量整数表达式。在对函数的调用中,整数表达式可能是 const 或 non-const 我想这(有效地)与在循环中声明和定义 VLA 时类似,即:
每次控制流通过声明时,都会计算表达式(并且它必须始终计算为大于零的值),并分配数组(相应地,VLA 的生命周期当声明超出范围时结束)。
(强调我的。)
...除了现在在函数调用时评估大小。
在您的特定情况下,您基本上有一个可变修改类型:
可变长度数组和从它们派生的类型(指向它们的指针等)通常称为“可变修改类型”(VM)。任何可变修改类型的对象只能在块范围或函数原型范围内声明。
是的,代码确实可以编译。一个例子:
#include <inttypes.h>
#include <stdio.h>
struct data_el
{
int n;
};
// Function prototype. Not specifying a size is allowed
void cistore(uint32_t bucketsize, struct data_el data[][*]);
// Function definition.
// Must specify the VLA's size as a non-constant integer expression
void cistore(uint32_t bucketsize, struct data_el data[][bucketsize])
{
(*data)[1].n = 5;
printf("%d\n", (*data)[1].n);
}
int main(void)
{
// Function call. Use any (const or non-const) integer expression.
uint32_t bucketsize = 2U;
struct data_el data[bucketsize];
cistore(bucketsize, &data);
}
有趣的是,Clang 编译它时没有警告,而 GCC 会警告类型冲突:
vlaquestion.c:14:50: warning: argument 2 of type ‘struct data_el[][bucketsize]’ declared as a variable length array [-Wvla-parameter]
14 | void cistore(uint32_t bucketsize, struct data_el data[][bucketsize])
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
vlaquestion.c:10:50: note: previously declared as an ordinary array ‘struct data_el[][0]’
10 | void cistore(uint32_t bucketsize, struct data_el data[][*]);
| ~~~~~~~~~~~~~~~^~~~~~~~~
最后,一些关于有争议的 VLA 的有用读物:Why aren't variable-length arrays part of the C++ standard?
在某些时候,甚至努力使 Linux 内核 VLA 免费。