如果一个系统不支持"产生负零",那么这句话的意思是什么?

20

C17 6.2.6.2/4说:

如果实现不支持负零,则使用将产生此类值的操作数的&、|、^、〜、<<和>>运算符的行为是未定义的。

如果我有一个二进制补码系统,它不支持负零。并且始终利用所有可能的二进制数字组合来表示一个值。因此,无论使用哪个位运算符,都不可能产生负零。那么这段文字的意思是什么呢?

我的理解是,该部分涉及到不支持负零的1的补码或有符号幅度系统,而是使用填充位或陷阱表示。这样理解正确吗?


你理解什么是“陷阱表示法”? - alinsoar
我也多次听说过“tr”,但从未真正见过,所以我无法理解它的含义。我读过关于这个的文章,但我不明白什么是陷阱表示。在X86处理器上有陷阱表示吗? - alinsoar
1
@alinsoar 我不知道现实世界中是否有任何使用它们来处理普通整数的实现(浮点数另当别论)。大多数情况下,这是由C标准委员会语言专家发明的东西,就像他们发明了需要支持1的补码和带符号计算机一样。 - Lundin
2
我不明白为什么会有复杂的答案,为什么这甚至是一个问题,难道它不是就像它所说的那样吗?你正在询问一个不包含负零概念的系统,那么那一部分描述的不就是_正是这个意思_吗?也就是说,就像你引用的那一部分所说...产生负零的行为(在你的情况下不存在的行为)具有未定义的结果。就这么简单。类比:颁布一项法律,规定“任何杀死鬼怪的人都要坐牢一周”,并不会因为缺乏鬼怪而突然变得混乱。 - Loduwijk
1
@Aaron 不完全是这样。在我的答案底部有一个示例,显示这种情况可能发生,当它发生时会引发未定义行为 - dbush
显示剩余2条评论
2个回答

15

是的,我认为您的理解是正确的。在二进制补码中,不存在可以产生负零的操作,因为这里的概念并不存在:任何带符号位的值必然小于0

顺便说一句:很可能奇异的符号表示法将从C2x中删除,所以所有这些都将消失。


1
我很惊讶编程语言设计者为什么如此担心向后的硬件兼容性。我认为在本世纪商业化的任何计算机硬件都只使用二进制补码表示法,而且可以相当确定没有人会为旧硬件编写新语言版本的编译器(相反,运行旧语言版本在新硬件上当然经常发生)。因此,语言设计者可以长期以来假定二进制补码行为,但显然他们现在才开始这样做。 - Marc van Leeuwen
@Jens,委员会是否正在考虑将二进制补码表示指定为唯一选项?另一种消除奇异符号表示的方法是删除细节,但仅当设置符号位时,使有符号整数的表示成为实现定义(甚至未指定)。 - John Bollinger
1
@MarcvanLeeuwen,问题在于很难评估是否仍存在这样的实现。而且,一如既往地,如果人们更多地参与委员会工作,事情可能会更顺利。 - Jens Gustedt
@JohnBollinger 是的,它应该是二进制补码,请参见http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2330.pdf。 - Jens Gustedt
2
@JohnBollinger:如果我可以自由选择,那么标准应该认可这样一种实现类别,即所有整数类型的表示都是一致的大端或小端,没有填充,并且有符号整数使用二进制补码。另外还有一种更广泛的类别,其中整数类型可以以任何实现所见的方式存储。我认为没有理由明确允许或排除更广泛类别中的任何特定表示形式。 - supercat

12

你的解释是正确的。

跳到 6.2.6.2 的第二段:

对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位。不需要任何填充位;signed char 不得具有任何填充位。必须恰好有一个符号位。每个是值位的位在相应的无符号类型的对象表示中都具有相同的值(如果有 M 个值位,则带符号类型的 N 位无符号类型中有 N ≥ M)。如果符号位为零,则它不会影响结果值。如果符号位为1,则值将以以下方式之一修改:

  • 对应的符号位为零的值被取反(符号-大小)
  • 符号位的值为 - (2M) (补码)
  • 符号位的值为 - (2M - 1) (反码)

其中适用哪种是实现定义的,以及带符号位为1且所有值位均为0(对于前两者)或带符号位和所有值位均为1(对于反码),是陷阱表示还是常规值,也是实现定义的。对于符号-大小和反码,如果该表示是正常值,则称为负零。

这意味着使用反码或符号-大小的实现对于给定大小的整数类型,必须具有特定表示形式,该表示形式必须是负零或陷阱表示。然后由实现选择其中之一适用。

例如,假设一个系统具有符号-大小表示和没有填充的32位 int。那么如果支持,则将成为负零的表示为 0x80000000

现在假设执行了以下操作:

 int x = 0x7fffffff;
 x = ~x;

如果实现支持负零,~ 运算符将生成 -0 作为结果并将其存储在 x 中。如果不支持,则创建陷阱表示,并按照第4段调用未定义的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接