Jas*_*son 9 c arrays variable-length-array
2011年标准明确规定......
6.7.6.2数组声明符
- 如果size是一个不是整数常量表达式的表达式:如果它出现在函数原型范围的声明中,则将其视为替换为
*
; 否则,每次评估它时,其值应大于零.可变长度数组类型的每个实例的大小在其生命周期中不会改变.如果size表达式是运算sizeof
符操作数的一部分,并且更改size表达式的值不会影响运算符的结果,则无法指定是否计算size表达式.
这是设计,但以下代码似乎是合理的.
size_t vla(const size_t x) {
size_t a[x];
size_t y = 0;
for (size_t i = 0; i < x; i++)
a[x] = i;
for (size_t i = 0; i < x; i++)
y += a[i % 2];
return y;
}
Run Code Online (Sandbox Code Playgroud)
Clang似乎为它生成合理的x64程序集(没有优化).显然索引零长度VLA没有意义,但访问超出边界会调用未定义的行为.
为什么零长度数组未定义?
int i = 0;
int a[i], b[i];
Run Code Online (Sandbox Code Playgroud)
是a == b
吗?它不应该 - 它们是不同的对象 - 但避免它是有问题的.如果你在无条件a
和b
无条件之间留下空隙,你就会浪费空间i > 0
.如果你检查是否i == 0
只留下间隙,那么你就是在浪费时间i > 0
.
多维数组会变得更糟:
int i = 0;
int a[2][i];
Run Code Online (Sandbox Code Playgroud)
你可以在两个变量之间填充,但你可以在哪里填充?没有破坏不变量就没有办法做到这一点sizeof (int[2][i]) == 2 * i * sizeof (int)
.如果不这样做垫,然后a[0]
与a[1]
具有相同的地址,你打破一个不同的重要不变.
这是一个不值得定义的头痛.
看看C标准:
[...] 如果表达式是常量表达式,则其值应大于零。[...]
如果大小是一个不是整数常量表达式的表达式:如果它出现在函数原型范围的声明中,则将其视为被
*
;替换。否则,每次评估时,其值都应大于零。[...]
如果违反了约束或运行时约束之外出现的“应”或“不应”要求,则行为是未定义的。未定义的行为在本国际标准中还用“未定义的行为”一词或省略任何明确的行为定义来表示。这三者的侧重点没有区别;它们都描述了“未定义的行为”。
因此,声明零大小的数组会导致程序的未定义行为。