是否需要在可能的情况下对三元运算符进行静态评估,还是编译器可以将其推迟到以后使用,从而拒绝依赖于其静态评估的程序?
更准确地说,这是程序的歧义片段:
char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0};
根据a
是否为可变长度数组,片段是否无效。如果a
是VLA,则sizeof(a)
不是静态确定的,因此无法进行初始化:
int main(int argc, char **argv) {
int a[argc];
char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0}; // invalid
return 0;
}
error: variable-sized object may not be initialized
但是,如果a
不是VLA,则可以静态评估所有内容:
int main() {
int a[42];
char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0}; // valid
return 0;
}
我的问题是:是否要求符合标准的编译器在可能的情况下进行静态评估,因此必须接受第二个程序,或者允许他们“将其推迟到动态评估”,并且可以拒绝吗?
答案 0 :(得分:5)
在第二种情况下:
int a[42];
char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0};
表达式sizeof(a) > 10 ? 10 : sizeof(a)
被视为C standard第6.6节中定义的常量表达式,也是整数常量表达式。
从6.6p3节开始,陈述了对一个常量表达式的约束:
常量表达式不得包含赋值,增量, 减,函数调用或逗号运算符,除非它们 包含在未评估的子表达式中。
上面的表达式不包含任何不允许的运算符。
第6.6p6节进一步详细说明了整数常量表达式:
整数常量表达式 117)必须具有整数类型,并且 只能具有整数常量,枚举常量,字符常量,
sizeof
表达式的操作数 其结果是整数常量,_Alignof
表达式,以及作为强制类型转换的立即数的浮点常量。将运算符转换为整数常量表达式 只能将算术类型转换为整数类型,除非 作为sizeof
操作数的一部分,或者_Alignof
运算符。
脚注117:
117)整数中需要整数常量表达式 上下文,例如一个位域成员的大小 结构,枚举常量的值,和大小 可变长度数组。适用于其他约束 条件包含中使用的整数常量表达式 预处理指令将在6.10.1中讨论
由于a
不是可变长度数组,因此sizeof(a)
的计算结果为整数常量。并且由于sizeof(a) > 10 ? 10 : sizeof(a)
仅包含10
(它是整数常量),因此sizeof(a)
(它的计算结果是整数常量)以及不允许的运算符?:
和>
运算符,整个表达式都被视为整数常量表达式,并且可以用作非可变长度数组的大小,这意味着您可以对其进行初始化。
答案 1 :(得分:4)
C标准未定义“静态评估”。
如果数组大小为整数常量表达式,则数组具有已知常量大小的完整类型。否则,它是一个可变长度的数组。
C 2018 6.6 6定义整数常量表达式:
整数常量表达式应为整数类型,并且仅应具有整数常量,枚举常量,字符常量,结果为整数常量
sizeof
的{{1}}表达式}表达式,以及作为强制类型转换的立即数的浮点常量。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为_Alignof
或sizeof
运算符的操作数的一部分。
因此,在_Alignof
中,问题是char b[sizeof(a) > 10 ? 10 : sizeof(a)]
是否具有整数常量。 C 6.5.3.4 2告诉我们:
sizeof(a)
运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的括号名称。大小由操作数的类型确定。结果是一个整数。如果操作数的类型是可变长度数组类型,则对操作数求值;否则,不对操作数求值,结果为整数常量。
因此,如果sizeof
不是可变长度数组,则结果是整数常量。如果a
是一个可变长度数组,则结果是一个整数,但不是一个隐式的整数常量。
因此,如果a
是一个可变长度数组,则a
声明一个可变长度数组。三元运算符的使用无关紧要,因为确定是基于以下事实:表达式包含的操作数不在6.6 6给出的列表中,而不是基于是否存在三元运算符。
如果char b[sizeof(a) > 10 ? 10 : sizeof(a)]
不是可变长度数组,则a
声明一个已知常量大小的数组。同样,三元运算符无关。 6.6 6中的确定未提及。因此,数组大小是一个常量整数表达式,并且符合C的C实现应接受char b[sizeof(a) > 10 ? 10 : sizeof(a)]
作为已知常量大小的数组并允许对其进行初始化。
以上是一个例外。 C 2018 6.6 10说:
实现可以接受其他形式的常量表达式。
因此,理论上,实现可以将b
定义为常量表达式。依赖于此当然不是便携式的。