C语言 C99中与常量表达式相关的未定义行为的含义和示例



我不明白C99中与常量表达式相关的未定义行为

例如:

要求为整型常量表达式的表达式没有整数类型;有非整数的操作数常量,枚举常量,字符常量,sizeof其结果为整型常量或立即强制转换的表达式浮动的常数;或包含将外部操作数强制转换为sizeof运算符),算术类型到整数类型的转换除外(6.6) .

我找不到这样的UB的例子?

此外,我不明白为什么常量表达式(在翻译时求值)不成为在运行时求值的表达式(而不是UB)。

这是从信息附件J中引用的。要找到实际的规范文本,您必须去附录J所指向的部分,在这种情况下,整数常量表达式C99 6.6:

的定义

整型常量表达式99)必须是整型且只能有操作数它们是整数常量,枚举常量,字符常量,sizeof表达式的结果是整型常量,浮点常量是强制转换的直接操作数

在我看来,这篇文章是不言自明的。也就是说:每当语法或规范文本在其他地方需要整数常量表达式时,无论您在这样的位置放置什么,都必须满足上面引用的部分,否则它不是整数常量表达式,而是未定义的行为。(违反a"应当";标准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之间的差异,作为两个对象在各自数据段中的偏移量之间的差异。这样的计算可能只有在对象恰好在相同的转换单元中定义时才有用,并且可能产生一个无意义的值,而不必发出诊断,如果它们不是。然而,编译器将无法知道对象是否在相同的翻译单元中定义,并且如果两个外部定义的对象在相同的编译单元中定义,而不是在相同的编译单元中定义,则标准将没有代码行为有意义定义的概念。基于标准管辖范围之外的标准,实现将在某些情况下定义的行为的标准术语是"未定义行为"。

最新更新