仍在与C(C99)未定义和未指定的行为作斗争。
这次是以下未指明行为(附录J.1):
在对象中存储值时使用的表示,该值具有多个对象表示(6.2.6.1)。
相应的部分6.2.6.1指出:
当一个运算符被应用于一个具有多个对象表示的值时,使用哪个对象表示不应影响结果的值43)。当一个值被存储在一个对象中时,使用一个类型,该类型具有该值的多个对象表示,未指定使用哪个表示,但不应生成陷阱表示。
注43:
具有相同有效类型T
的对象x
和y
在作为类型T
的对象访问时可能具有相同的值,但在其他上下文中具有不同的值。特别是,如果==
是为T
类型定义的,那么x == y
并不意味着memcmp(&x, &y, sizeof(T)) == 0
。此外,x == y
不一定意味着x
和y
具有相同的值;对类型T
的值的其它操作可以在它们之间进行区分。
我甚至不明白什么是 * 一个有多个对象表示的值 *。例如,它是否与0(负零和正零)的浮点表示有关?
3条答案
按热度按时间epfja78i1#
这种语言的大部分是C标准,它很好地允许在Burroughs B系列大型机上继续使用(AFAICT是唯一幸存的一补体系结构)。除非你不得不使用那些或某些不常见的微控制器,或者你认真地进行了回溯计算,否则你可以安全地假设整数类型每个值只有一个对象表示,并且它们没有填充位。您还可以安全地假设所有整数类型都没有陷阱表示,* 除了 * 您必须采用J.2的这一行
[the如果...,则行为未定义]具有自动存储持续时间的对象的值在不确定时被使用
好像它是规范的,好像被划掉的词不存在。(仔细阅读实际的规范文本并不支持这条规则,但它仍然是当前所有优化编译器所采用的规则。
在现代的、非外来的实现中,* 可以 * 对一个值有多个对象表示的类型的具体例子包括:
_Bool
:未指定用适当大小的0或1以外的整数值表示重写_Bool
对象的效果。(int*)0x8000_0000
和(int*)0x8000_0001
可以被视为引用相同的int
对象;这是一个有意的硬件特征,便于使用标记指针)这些也是在现代实现中可以具有陷阱表示的标量类型。特别是,附录F明确声明了NaN的行为是未定义的,即使它在IEC 60559的抽象实现中定义良好。
1l5u6lss2#
我甚至不明白什么是具有多个对象表示的值。例如,它是否与0(负零和正零)的浮点表示有关?
否,负零和正零是不同的值。
在实践中,您可能不需要担心具有不同对象表示的值,但是一个可能的示例将涉及包含填充位的整数类型。例如,假设您的实现提供了一个15(值)位无符号整数类型,其存储大小为16位。还假设为了计算对象的目的,该类型的表示中的填充位被完全忽略(即,该类型不提供陷阱表示)。然后,该类型可表示的每个值将具有两个不同的对象表示,不同的是填充位的值。
该标准规定,在这种情况下,您不能依赖于在任何给定情况下在这些值表示之间进行的特定选择,但是当这些对象是任何C操作符的操作数时,这并不重要。注43澄清说,这种差别可能在其他方面也能感觉到。
6ss1mwsb3#
正如您所怀疑的,
-0.0
是一个很好的候选者,但仅适用于最后一个短语:此外,
x == y
不一定意味着x
和y
具有相同的值;对类型T
的值的其它操作可以在它们之间进行区分。字符串
具有多于一个可能表示的值的另一示例是NaN。
0.0 / 0.0
的计算结果为NaN值,该值可能与宏NAN
或其他生成NaN的操作产生的表示不同,甚至可能与再次计算的相同表达式0.0 / 0.0
的表示不同。memcmp()
可以显示表示不同。然而,这个例子并没有真正说明标准在问题中引用的目的,因为这些值并不匹配==
运算符。您从附录J中引用的文本似乎专门针对一些罕见的架构(现在),这些架构具有填充位和/或负数的表示,对于
0
有2种不同的表示。所有现代系统都使用two's complement来表示负数,其中所有位模式表示不同的值,但40年前,一些相当常见的大型机使用ones' complement或符号和幅度,其中2种不同的位模式可以表示值0
。