微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

关于“具有多个对象表示的对象”的未指定行为

如何解决关于“具有多个对象表示的对象”的未指定行为

仍在努力应对 C (C99) 未定义和未指定的行为。

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

在对象中存储值时使用的表示 该值的多个对象表示 (6.2.6.1)。

相应的第 6.2.6.1 节指出:

运算符应用于具有多个对象的值的地方 表示,使用哪种对象表示不应影响 结果的值43)。使用值将值存储在对象中的位置 一种对该值具有多个对象表示的类型,它 未指定使用哪种表示,而是陷阱表示 不得生成

带有以下注释 43:

具有相同有效类型 x 的对象 yT 是可能的 当它们作为 T 类型的对象访问时具有相同的值,但是 在其他情况下具有不同的价值。特别是,如果 == 是 为类型 T 定义,那么 x == y 并不意味着 memcmp(&x,&y,sizeof(T)) == 0。此外,x == y 并不一定意味着 xy 具有相同的值;对 T 类型的值的其他操作可能 区分它们。

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

解决方法

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

[行为未定义如果 ...] 一个对象的值具有自动存储持续时间在它不确定时被使用

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

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

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

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

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

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

,

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

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

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

标准规定,在这种情况下,您不能依赖于在任何给定情况下在这些值表示之间进行特定选择,而且这些对象是否是任何 C 运算符的操作数都无关紧要。注释 43 澄清了差异可能会以其他方式感受到。

,

如您所料,-0.0 是一个不错的候选词,但仅适用于最后一句话:

此外,x == y 并不一定意味着 xy 具有相同的值;对 T 类型的值的其他操作可能会区分它们。

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 中引用的文本似乎专门解决了一些罕见的架构(现在),这些架构具有填充位和/或负数的表示,以及 0 的 2 种不同表示。所有现代系统都使用 two's complement 来表示负数,其中所有位模式表示不同的值,但是 4 年前,您一些相当常见的大型机使用 ones' complementsign and magnitude,其中 2 种不同的位模式可以表示值 0

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。