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

1mrurvl1  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(86)

仍在与C(C99)未定义和未指定的行为作斗争。
这次是以下未指明行为(附录J.1):
在对象中存储值时使用的表示,该值具有多个对象表示(6.2.6.1)。
相应的部分6.2.6.1指出:
当一个运算符被应用于一个具有多个对象表示的值时,使用哪个对象表示不应影响结果的值43)。当一个值被存储在一个对象中时,使用一个类型,该类型具有该值的多个对象表示,未指定使用哪个表示,但不应生成陷阱表示。
注43:
具有相同有效类型T的对象xy在作为类型T的对象访问时可能具有相同的值,但在其他上下文中具有不同的值。特别是,如果==是为T类型定义的,那么x == y并不意味着memcmp(&x, &y, sizeof(T)) == 0。此外,x == y不一定意味着xy具有相同的值;对类型T的值的其它操作可以在它们之间进行区分。
我甚至不明白什么是 * 一个有多个对象表示的值 *。例如,它是否与0(负零和正零)的浮点表示有关?

epfja78i

epfja78i1#

这种语言的大部分是C标准,它很好地允许在Burroughs B系列大型机上继续使用(AFAICT是唯一幸存的一补体系结构)。除非你不得不使用那些或某些不常见的微控制器,或者你认真地进行了回溯计算,否则你可以安全地假设整数类型每个值只有一个对象表示,并且它们没有填充位。您还可以安全地假设所有整数类型都没有陷阱表示,* 除了 * 您必须采用J.2的这一行
[the如果...,则行为未定义]具有自动存储持续时间的对象的值在不确定时被使用
好像它是规范的,好像被划掉的词不存在。(仔细阅读实际的规范文本并不支持这条规则,但它仍然是当前所有优化编译器所采用的规则。
在现代的、非外来的实现中,* 可以 * 对一个值有多个对象表示的类型的具体例子包括:

  • _Bool:未指定用适当大小的0或1以外的整数值表示重写_Bool对象的效果。
  • 指针类型:一些体系结构忽略指向其最小对齐大于1的类型的指针的低位(例如,(int*)0x8000_0000(int*)0x8000_0001可以被视为引用相同的int对象;这是一个有意的硬件特征,便于使用标记指针)
  • 浮点类型:IEC 60559允许NaN的所有许多表示被硬件相同地处理(并且可能被挤压在一起)。(注意:+0和-0是IEEE浮点数中的不同值,而不是同一值的不同表示。

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

1l5u6lss

1l5u6lss2#

我甚至不明白什么是具有多个对象表示的值。例如,它是否与0(负零和正零)的浮点表示有关?
否,负零和正零是不同的值。
在实践中,您可能不需要担心具有不同对象表示的值,但是一个可能的示例将涉及包含填充位的整数类型。例如,假设您的实现提供了一个15(值)位无符号整数类型,其存储大小为16位。还假设为了计算对象的目的,该类型的表示中的填充位被完全忽略(即,该类型不提供陷阱表示)。然后,该类型可表示的每个值将具有两个不同的对象表示,不同的是填充位的值。
该标准规定,在这种情况下,您不能依赖于在任何给定情况下在这些值表示之间进行的特定选择,但是当这些对象是任何C操作符的操作数时,这并不重要。注43澄清说,这种差别可能在其他方面也能感觉到。

6ss1mwsb

6ss1mwsb3#

正如您所怀疑的,-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来表示负数,其中所有位模式表示不同的值,但40年前,一些相当常见的大型机使用ones' complement或符号和幅度,其中2种不同的位模式可以表示值0

相关问题