标准说(C17,6.5.3.4¶2):
运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或带括号的类型名称。大小由操作数的类型确定。结果是一个整数。如果操作数的类型是变长数组类型,则对操作数求值;否则,不计算操作数,结果是整数常量。sizeof
令人困惑的是,措辞并没有区分
sizeof
的两个语法上下文:
sizeof
一元表达式sizeof(
类型名称)
我相信 type-name 从技术上讲并不“具有”类型,而是“表示”(名称、指定)类型。另外,在类型名称作为参数的情况下,我会直观地用评估其中的所有赋值表达式来表达这一点——如果不是为了准确性,那么为了清晰起见。
无论如何,我理解这个措辞的意思是,在
sizeof(type)
的情况下,type
中的所有表达式都将被精确计算,如果(ie: 当且仅当)type
表示 VLA(可变长度)数组)类型。
考虑到上述内容,以下代码的最后一个
printf
语句具有令人惊讶的结果:
#include <stdio.h>
void f(int i) {
printf("side effect %d; ", i);
}
int main(void) {
int n = 9;
int a[n];
printf("%zu\n", sizeof a); // 36
printf("%zu\n", sizeof a[n++]); // 4
printf("%d\n", n); // 9
printf("%zu\n", sizeof(int [n++])); // 36
printf("%d\n", n); // 10
printf("%zu\n", sizeof(int [(f(0), 100)]));
// side effect 0; 400 (type of operand: int, a non-VLA type)
return 0;
}
(
int i
的参数f
- 在问题标题中省略 - 用于调试目的和玩耍,如果有人想区分对该函数的不同调用。)
int [(f(0), 100)]
是int [100]
类型,它不是数组类型。那么:为什么f(0)
会被评估?type_name
中的 sizeof(type_name)
(或其中的表达式)的确切条件是什么?顺便说一句,
sizeof(int [f(0), 100])
(表示数组大小的逗号表达式周围没有括号)会导致错误,我在以下问题中讨论:如果作为数组大小的一部分,为什么必须将用作数组大小的逗号表达式括在括号中数组声明符?
标准(C17 草案)中讨论数组声明符语法的相关位置包括:6.7.7 ¶1、6.7.6.2 ¶3.
Keith Thompson 对有关 VLA 的问题的这个回答是相关的。但请注意,我的问题不是关于 VLA 本身(尽管它在上面的代码中使用它们用于对比目的)。
根据C17标准(6.6常量表达式):
2 常量表达式可以在翻译过程中进行计算,而不是 比运行时,因此可以在任何地方使用 可能是常数。
和
3 常量表达式不得包含赋值、自增、 递减、函数调用或逗号运算符,除非它们是 包含在未计算的子表达式中。1
就像这个表达一样
sizeof(int [(f(0), 100)])
带有逗号运算符的子表达式
(f(0), 100)
不是数组声明中的常量子表达式,则声明了一个可变长度数组,其大小在 runtome 中计算。