C99中与常量表达式相关的未定义行为的含义和示例
Meaning and example of Undefined behaviours related to constant expression in C99
我不明白 C99 中与常量表达式相关的未定义行为。
例如:
An expression that is required to be an integer constant expression
does not have an integer type; has operands that are not integer
constants, enumeration constants, character constants, sizeof
expressions whose results are integer constants, or immediately-cast
floating constants; or contains casts (outside operands to sizeof
operators) other than conversions of arithmetic types to integer types
(6.6).
我找不到此类 UB 的示例?
此外,我不明白为什么常量表达式(在翻译时求值)不会变成在运行时求值的表达式(而不是 UB)。
这是从信息性附件J中引用的。要找到实际的规范性文本,您必须转到附录J所在的部分指向,在这种情况下 整数常量表达式 C99 6.6:
的定义
An integer constant expression99) shall have integer type and shall only have operands
that are integer constants, enumeration constants, character constants, sizeof
expressions whose results are integer constants, and floating constants that are the
immediate operands of casts.
在我看来,这段文字是不言自明的。即:每当别处的语法或规范文本需要整型常量表达式时,无论你放在这样的位置什么都必须满足上面引用的部分,否则它不是整型常量表达式而是未定义的行为。 (违反规范 ISO C 文本中的“应”要求始终是 UB。)
我希望编译器善于为此给出错误,因为它是编译时 UB。
例如,这是无效的,因为具有静态存储持续时间的数组声明要求大小为整数常量表达式:
int a=1;
static int x [a];
同样,int x [1 + 1.0];
无效,但 int x[1 + (int)1.0];
可以。
根据 N1570 6.6p10,“实现可以接受其他形式的常量表达式。”通常,允许实现拒绝程序但也允许接受程序的情况被归类为未定义行为。虽然指定一个实现可能会有所帮助(在文件范围内):
int x,y;
int sz = (uintptr_t)&y - (uintptr_t)&x;
将被要求拒绝该程序,或者表现得好像 sz
被初始化为一个值,该值与如果指定的转换和减法将在运行时执行时将计算的值相匹配,这样的构造通常会需要链接器支持,编译器可能无法确定链接器支持哪些结构,或者如果代码使用不支持的结构它会做什么。
该标准不使用术语“未定义的行为”纯粹指代错误的构造,而是将其应用于不可移植的构造,这些构造在某些实现上可能不受支持或错误,但在其他实现上是正确的。该标准的作者指出,除其他事项外,未定义行为通过允许实现定义超出标准强制要求的行为来识别“符合语言扩展”的潜在领域。从这个角度来看,将非标准形式的整数常量表达式的处理归类为未定义行为允许编译器在实际和有用时支持此类构造,而无需对某些实现可能无法满足的此类构造的行为强加要求。
回到前面的示例,编译器可能会将 &y
和 &x
之间的差异计算为两个对象在其各自数据部分中的偏移量之间的差异。这样的计算可能仅在对象碰巧在同一个翻译单元中定义时才有用,并且可能产生无意义的值,如果不是,则不一定发出诊断。然而,编译器无法知道对象是否在同一个翻译单元中定义,并且如果在同一个编译单元中定义了两个外部定义的对象,标准将没有代码的概念,其行为将被有意义地定义,但如果不是,则不会。根据标准管辖范围之外的标准,实现在某些情况下而不是在其他情况下定义的行为的标准术语是“未定义的行为”。
我不明白 C99 中与常量表达式相关的未定义行为。
例如:
An expression that is required to be an integer constant expression does not have an integer type; has operands that are not integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, or immediately-cast floating constants; or contains casts (outside operands to sizeof operators) other than conversions of arithmetic types to integer types (6.6).
我找不到此类 UB 的示例?
此外,我不明白为什么常量表达式(在翻译时求值)不会变成在运行时求值的表达式(而不是 UB)。
这是从信息性附件J中引用的。要找到实际的规范性文本,您必须转到附录J所在的部分指向,在这种情况下 整数常量表达式 C99 6.6:
的定义An integer constant expression99) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts.
在我看来,这段文字是不言自明的。即:每当别处的语法或规范文本需要整型常量表达式时,无论你放在这样的位置什么都必须满足上面引用的部分,否则它不是整型常量表达式而是未定义的行为。 (违反规范 ISO C 文本中的“应”要求始终是 UB。)
我希望编译器善于为此给出错误,因为它是编译时 UB。
例如,这是无效的,因为具有静态存储持续时间的数组声明要求大小为整数常量表达式:
int a=1;
static int x [a];
同样,int x [1 + 1.0];
无效,但 int x[1 + (int)1.0];
可以。
根据 N1570 6.6p10,“实现可以接受其他形式的常量表达式。”通常,允许实现拒绝程序但也允许接受程序的情况被归类为未定义行为。虽然指定一个实现可能会有所帮助(在文件范围内):
int x,y;
int sz = (uintptr_t)&y - (uintptr_t)&x;
将被要求拒绝该程序,或者表现得好像 sz
被初始化为一个值,该值与如果指定的转换和减法将在运行时执行时将计算的值相匹配,这样的构造通常会需要链接器支持,编译器可能无法确定链接器支持哪些结构,或者如果代码使用不支持的结构它会做什么。
该标准不使用术语“未定义的行为”纯粹指代错误的构造,而是将其应用于不可移植的构造,这些构造在某些实现上可能不受支持或错误,但在其他实现上是正确的。该标准的作者指出,除其他事项外,未定义行为通过允许实现定义超出标准强制要求的行为来识别“符合语言扩展”的潜在领域。从这个角度来看,将非标准形式的整数常量表达式的处理归类为未定义行为允许编译器在实际和有用时支持此类构造,而无需对某些实现可能无法满足的此类构造的行为强加要求。
回到前面的示例,编译器可能会将 &y
和 &x
之间的差异计算为两个对象在其各自数据部分中的偏移量之间的差异。这样的计算可能仅在对象碰巧在同一个翻译单元中定义时才有用,并且可能产生无意义的值,如果不是,则不一定发出诊断。然而,编译器无法知道对象是否在同一个翻译单元中定义,并且如果在同一个编译单元中定义了两个外部定义的对象,标准将没有代码的概念,其行为将被有意义地定义,但如果不是,则不会。根据标准管辖范围之外的标准,实现在某些情况下而不是在其他情况下定义的行为的标准术语是“未定义的行为”。