在C中表示负数?

1s2*_*e7v 22 c negative-number twos-complement language-lawyer

C如何表示负整数?

它是通过二进制补码表示还是使用MSB(最重要的位)?

-1十六进制是ffffffff.

所以请为我澄清一下.

pax*_*blo 42

ISO C(C99 section 6.2.6.2/2在这种情况下,但它延续到标准(a)的后续迭代)表明实现必须选择三种不同表示中的一种用于积分数据类型,二进制补码,一些补码或符号/幅度(尽管它非常令人难以置信)很可能两者的补充实施远远超过其他实施).

在所有这些表示中,正数是相同的,唯一的区别是负数.

要获得正数的负面表示,您:

  • 反转所有位然后加一个用于二进制补码.
  • 将所有位反转为1的补码.
  • 仅反转符号位的符号/幅度.

您可以在下表中看到:

number | two's complement    | ones' complement    | sign/magnitude
=======|=====================|=====================|====================
     5 | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101
    -5 | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101

请记住,ISO并未强制要求在表示中使用所有位.它们引入了符号位,值位和填充位的概念.现在我从未真正看到过使用填充位的实现,但是从C99原理文档中,他们有这样的解释:

假设一台机器使用一对16位短路(每个都有自己的符号位)来构成一个32位的int,并且在这个32位int中使用时,忽略较低short的符号位.然后,作为32位有符号整数,在确定32位有符号int的值时会忽略一个填充位(在32位的中间).但是,如果将此32位项目视为32位无符号整数,则该填充位对用户程序可见.C委员会被告知有一台机器以这种方式工作,这就是填充位被添加到C99的一个原因.

我相信他们可能提到的机器是Datacraft 6024(它是Harris Corp的继承者).在那些机器中,你有一个用于有符号整数的24位字,但是,如果你想要更宽的类型,它将它们中的两个串在一起作为47位值,其中一个字的符号位被忽略:

+---------+-----------+--------+-----------+
| sign(1) | value(23) | pad(1) | value(23) |
+---------+-----------+--------+-----------+
\____________________/ \___________________/
      upper word            lower word
Run Code Online (Sandbox Code Playgroud)

(a)有趣的是,鉴于实际使用其他两种方法的现代实现的稀缺性,已经推动将两个补码接受为一种真正的方法.这在C++标准中已经走了很长的路(WG21是负责这个的工作组),现在显然也被考虑用于C(由WG14).

  • @FrerichRaabe 直接来自维基百科“二进制算术不起作用。” 本质上,加法器如何知道它的负数和正数。http://simple.wikipedia.org/wiki/Signed_number_representations (2认同)

Jer*_*fin 12

C允许有符号整数的符号/幅度,一个补码和二进制补码表示.大多数典型硬件对整数使用二进制补码,对浮点使用符号/幅度(另一种可能性 - 浮点指数的"偏差"表示).


Cli*_*ord 7

十六进制中的-1是ffffffff.所以请在这方面澄清我.

在二进制补码(迄今为止最常用的表示)中,除最高有效位(MSB)之外的每个位,从右到左(递增的数量级)具有值2 n,其中n从零增加1.MSB的值为-2 n.

因此,例如在8位二进制补码整数中,MSB的位值为-2 7(-128),因此二进制数:1111 1111 2等于-128 + 0111 1111 2 = -128 + 127 = -1

二进制补码的一个有用特性是处理器的ALU只需要一个加法器块来执行减法,方法是形成右手操作数的二进制补码.例如10 - 6相当于10 +( - 6); 在8位二进制文​​件中(为了简化说明),这看起来像:

   0000 1010
  +1111 1010
   ---------
[1]0000 0100  = 4 (decimal)
Run Code Online (Sandbox Code Playgroud)

其中[1]是丢弃的进位.另一个例子; 10 - 11 == 10 +( - 11):

   0000 1010
  +1111 0101
   ---------
   1111 1111  = -1 (decimal)
Run Code Online (Sandbox Code Playgroud)

二进制补码的另一个特点是它有一个代表零的值,而符号量和一个补码各有两个; +0和-0.