根据cppreference:
如果表达式的类型是可变长度数组类型, 表达式 被评估并计算它评估的数组的大小 在运行时。
这意味着:如果表达式的类型是VLA类型,则评估表达式。例如:
#include <stdio.h>
int main() {
int i = 0;
int a[i];
printf("%zu\n",sizeof(a[i++]));
printf("%d\n",i); // Here, print 0 instead of 1
return 0;
}
因此,根据参考资料,此处i
变为1
。但是,使用我的GCC编译器,i
打印为0
。
请参阅Wandbox Demo。
答案 0 :(得分:19)
首先,请注意,数组的大小不能为零,无论是否为VLA。所以你的代码会调用未定义的行为。
C11 6.7.6.2/5
“如果大小是一个不是整数常量表达式的表达式:”/ - /“......每次计算它时,它的值应大于零。”
对于实际问题,a[i++]
的类型为int
,而不是VLA类型。
为了获得副作用,您必须参与VLA数组类型本身,例如sizeof(a)
。只有这样才能评估操作数的副作用。一个例子来说明这一点:
#include <stdio.h>
int main() {
int i=1, j=1;
int a[i][j];
int b[1][1];
(void) sizeof(a[--i]);
(void) sizeof(b[--j]);
printf("%d %d", i, j);
return 0;
}
此处i
由于VLA导致第一个sizeof
被评估,因此结果为0,但j
仍为1,因为--j
是sizeof
的一部分对于常规数组。
答案 1 :(得分:9)
示例中sizeof的表达式是int,而不是vla。如果它是vla,那么一切都会起作用:
#include <stdio.h>
int main() {
int i = 5;
int a[i][i];
printf("%zu\n",sizeof(a[--i]));
printf("%d\n",i); // Here, print 4
return 0;
}
答案 2 :(得分:3)
来自C Standards#6.5.3.4p2 [强调我的]
sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称。大小由操作数的类型确定。 结果是整数。如果操作数的类型是可变长度数组类型,则计算操作数;否则,不评估操作数,结果是整数常量。
在表达式中:
sizeof(a[i++])
a[i++]
不是VLA,而是下标运算符表达式,导致整数。因此,操作数未被评估,出于同样的原因,编译器在此语句上发出警告:
warning: expression with side effects has no effect in an unevaluated context
答案 3 :(得分:3)
对它进行规范性引用的克隆:
6.5.3.4 - The sizeof and _Alignof operators
sizeof运算符产生其操作数的大小(以字节为单位) 可以是表达式或类型的带括号的名称。大小是 根据操作数的类型确定。结果是整数。如果 操作数的类型是可变长度数组类型,操作数 被评估;否则,不评估操作数和结果 是一个整数常量。
如果您修复示例以生成具有VLA类型的表达式,则会对其进行评估
$PATH
Prints 2
on the last line,因为#include <stdio.h>
int main() {
int i = 1;
int a[5][i];
printf("%zu\n",sizeof(a[i++]));
printf("%d\n",i);
return 0;
}
会增加。