关于 "object having more than one object representation" 的未指定行为

Unspecified behaviour about "object having more than one object representation"

仍在与 C (C99) 未定义和未指定的行为作斗争。

这次是以下未指定的行为(附件 J.1):

The representation used when storing a value in an object that has more than one object representation for that value (6.2.6.1).

相应的第 6.2.6.1 节指出:

Where an operator is applied to a value that has more than one object representation, which object representation is used shall not affect the value of the result43). Where a value is stored in an object using a type that has more than one object representation for that value, it is unspecified which representation is used, but a trap representation shall not be generated.

附注 43:

It is possible for objects x and y with the same effective type T to have the same value when they are accessed as objects of type T, but to have different values in other contexts. In particular, if == is defined for type T, then x == y does not imply that memcmp(&x, &y, sizeof(T)) == 0. Furthermore, x == y does not necessarily imply that x and y have the same value; other operations on values of type T may distinguish between them.

我什至不明白什么是具有多个对象表示的值。它是否与 0(负零和正零)的浮点表示有关?

如您所料,-0.0 是一个不错的候选者,但仅适用于最后一个短语:

Furthermore, x == y does not necessarily imply that x and y have the same value; other operations on values of type T may distinguish between them.

double x = 0.0;
double y = -0.0;
if (x == y) {
    printf("x and y have the same value\n");
}
if (memcmp(&x, &y, sizeof(double)) {
    printf("x and y have a different representation\n");
}
if (1 / x != 1 / y) {
    printf("1/x and 1/y have a different value\n");
}

具有多种可能表示的值的另一个示例是 NaN。 0.0 / 0.0 的计算结果为 NaN 值,该值可能与宏 NAN 或另一个产生 NaN 的操作产生的表示不同,甚至相同的表达式 0.0 / 0.0 再次计算。 memcmp() 可能表明表述不同。然而,这个例子并没有真正说明标准在问题中引用的目的,因为这些值与 == 运算符不匹配。

你从附件 J 中引用的文本似乎专门针对一些罕见的架构(现在),这些架构具有填充位 and/or 负数表示和 0 的 2 种不同表示。所有现代系统都使用 two's complement to represent negative numbers, where all bit patterns represent different values, but 4 decades ago you some fairly common mainframes used ones' complement or sign and magnitude,其中 2 个不同的位模式可以表示值 0.

I don't even understand what would be a value that has more than one object representation. Is it related for example to a floating point representation of 0 (negative and positive zero) ?

不是,负零和正零是不同的值。

在实践中,您可能不需要担心具有不同对象表示的值,但一个可能的示例将涉及包含填充位的整数类型。例如,假设您的实现提供了一个 15(值)位的无符号整数类型,其存储大小为 16 位。还假设出于评估对象的目的,该类型表示中的填充位被完全忽略(即,该类型不提供陷阱表示)。然后该类型可表示的每个值将有两个不同的对象表示,不同之处在于填充位的值。

标准规定,在这种情况下,您不能依赖于在任何给定情况下在这些值表示之间做出的特定选择,而且当此类对象是任何 C 运算符的操作数时也无关紧要.附注 43 阐明了这种差异可能会在其他方面感受到。

大多数这种语言都是 C 标准,以允许在 Burroughs B 系列大型机上继续使用(AFAICT 幸存的补码架构)。除非您必须使用那些或某些不常见的微控制器,或者您认真地进行逆向计算,否则您可以安全地假设整数类型的每个值只有一个对象表示,并且它们没有填充位。您还可以安全地假设所有整数类型都没有陷阱表示,除了您必须采用 J.2

的这一行

[the behavior is undefined if ...] the value of an object with automatic storage duration is used while it is indeterminate

就好像它是规范的,就好像划掉的词不存在一样。 (仔细阅读实际的规范文本并不支持这条规则,但它仍然是当前所有优化编译器所采用的规则。)

可以在现代的、非奇特的实现中具有多个值的对象表示的具体示例包括:

  • _Bool:未指定用适当大小的 0 或 1 以外的整数值表示覆盖 _Bool 对象的效果。

  • 指针类型:一些架构忽略指向最小对齐大于1的类型的指针的低位(例如(int*)0x8000_0000(int*)0x8000_0001 可能被视为指代相同的 int 对象;这是一项有意的硬件功能,便于使用标记指针)

  • 浮点类型:IEC 60559 允许硬件对 NaN 的所有许多表示进行相同的处理(并可能压缩在一起)。 (注意:+0 和 −0 是 IEEE 浮点数中的不同值,不是相同值的不同表示。)

这些也是在现代实现中可以具有陷阱表示的标量类型。特别是,附件 F 明确声明发信号 NaN 的行为未定义,即使它在 IEC 60559 的抽象实现中有明确定义。