具有可变长度数组类型的 Sizeof 运算符
Posted
技术标签:
【中文标题】具有可变长度数组类型的 Sizeof 运算符【英文标题】:Sizeof operator with variable-length array type 【发布时间】:2018-07-17 13:56:39 【问题描述】:据cppreference:
如果表达式的类型是变长数组类型,表达式 被评估并计算它评估的数组的大小 在运行时。
意思是:如果expression的类型是VLA类型,则expression被求值。例如:
#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。
【问题讨论】:
a[i++]
不是 VLA 类型的表达式。它最终是一个下标表达式,类型为int
。除此之外,即使是 VLA 的 a[0]
也是违反约束的。
VLA 的长度在定义时确定。在上面的代码中,长度将为 0,因此 VLA 将没有元素。大小在定义后不会改变。此外,长度需要大于零,否则是未定义行为。
@byxor - C++ 除了作为编译器扩展之外没有它们(因为编译器也支持 C)。
Why does sizeof(x++) not increment x?的可能重复
这是关于sizeof+vla的,不是那个问题的重复
【参考方案1】:
首先,请注意数组的大小不能为零,无论它是否是 VLA。所以你的代码会调用未定义的行为。
C11 6.7.6.2/5
"如果 size 是一个不是整数常量表达式的表达式:" /--/ "...每次对其求值时,它的值应大于零。"
至于实际问题,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
最终为 0,因为第一个 sizeof
由于 VLA 被评估,但 j
仍然为 1,因为 --j
是常规数组的 sizeof
的一部分。
【讨论】:
偏离原始问题的主题,但知道为什么该标准为 VLA 类型的表达式提供特殊情况吗? @Ajay 假设int a[i];
,表达式sizeof a
必须能够在运行时计算出正确的结果,因为i
的值在编译时是未知的。
@AjayBrahmakshatriya 因为大小只在运行时设置,所以不一定在编译时预先计算。
@Lundin,它只需要 sizeof a[--i]
的值作为运行时值。无需评估操作数。从操作数的类型而不是从其值推断的大小【参考方案2】:
您的示例中 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;
【讨论】:
【参考方案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
【讨论】:
【参考方案4】:取一个规范性引用的克隆词为它:
6.5.3.4 - The sizeof and _Alignof operators
sizeof 运算符产生其操作数的大小(以字节为单位),即 可以是表达式或类型的括号名称。尺寸是 由操作数的类型决定。结果是一个整数。如果 操作数的类型是变长数组类型,操作数 被评估;否则,不计算操作数并且结果 是一个整数常量。
如果您修复示例以生成具有 VLA 类型的表达式,它将被评估,其中一种方式
#include <stdio.h>
int main()
int i = 1;
int a[5][i];
printf("%zu\n",sizeof(a[i++]));
printf("%d\n",i);
return 0;
Prints 2
on the last line,因为i
递增。
【讨论】:
以上是关于具有可变长度数组类型的 Sizeof 运算符的主要内容,如果未能解决你的问题,请参考以下文章