【问题标题】:C and signed byte representation in memory内存中的 C 和有符号字节表示
【发布时间】:2013-08-02 09:38:42
【问题描述】:

有些东西我不明白:

C 中的signed char 用 8 位表示:00000000

  • 0 是0000 0000 => 0
  • 1 是0000 0001 => 1
  • ...
  • 127 是0111 1111 => 127

所以我认为第 8 位是符号位。 所以我想:

  • 128 是1000 0000 => 0
  • 129 是1000 0001 => -1

但是没有!

试试这个:

int main(int argc, const char *argv[])
{
    int i;
    for (i = 0; i < 256; i++) {
        printf("%3d = %d\n", i, (signed char)i);
    }
    return 0;
}

你会得到:gcc -o tt tt.c ; ./tt | more

  • ...
  • 126 = 126
  • 127 = 127
  • 128 = -128
  • 129 = -127
  • 130 = -126
  • 254 = -2
  • 255 = -1

怎么来的?

【问题讨论】:

  • 了解Two's complement
  • 您描述的符号幅度方案确实存在,但整数很少见,因为它使算术复杂化。二进制补码使许多操作与符号无关。
  • @GrijeshChauhan 显着未定义,如果您将自己限制为 8 位(这不是一个可表达的数字,但如果您盲目地应用如何使用 2-补码来否定数字的规则,您最终会得到 - (-128) -> -128.
  • @Vatine 你是正确的位溢出是未定义的,它实际上是实现定义的,因为一个陷阱表示。我只是试图回答特定的输出。

标签: c byte


【解决方案1】:

这称为有符号整数的 2 的补码表示,适用于所有整数类型。

这个想法是这样的:CPU 中的加法器会在发生溢出时忽略并回绕,因此您实际上是在一个模数环上进行计算。所以,如果你从零中减去 1,你会得到

 00000000 = 0
-00000001 = 1
--------------
 11111111 = -1

等等。

这样,您的计算机在计算时可以简单地忽略符号。甚至乘法也是如此,如本例中 3 和 -2 的乘法(为简洁起见,为 4 位算术):

0011 * 1110
-----------
       0000
      0011
     0011
    0011
-----------
     101010
truncated to 4 bits: 1010

10100110 的负数,即 6,所以结果应该是 -6。

只有很少的点需要考虑符号性,例如比较、除法和转换为更大的整数类型。比较相对简单,演员表的工作方式如下:

00000001 -> 0000000000000001
10000000 -> 0000000010000000 (unsigned extension 128 -> 128)
10000000 -> 1111111110000000 (sign extension, the sign bit is copied into all new bits, preserving the value of negative numbers -128 -> -128)

【讨论】:

  • @glglgl 你的意思是:10000000 -&gt; 0000000010000000?不,没有错,它是 unsigned 扩展名。
  • 好吧,我看错了。我将其视为-00000001 = 1 的声明,这是不正确的。我不明白这是完整行的- 符号。
  • 但是对于您的最后一个主张 - 还有两点:乘法和除法。 x / -1 不是 x / 255x * -1x * 255 的计算相同。
  • @glglgl 我相信您对部门的看法是正确的,抱歉我忘记了这些。但是对于乘法的情况,我的断言是正确的,因为任何时间 2^n 的最后 n 位都会被清除。如果你从这个因子中去掉一个因子,你就从结果中减去另一个因子,这是它在 2 的补码表示中的负数。用 2 的补码计算是多么容易,真是令人惊讶……
  • 糟糕——我认为你是对的。实际上,256 * 255 和 256 * -1 都导致 0xFF00...
【解决方案2】:

这是因为 8 位 2 的补码编码。带符号的字符范围是 -128 到 127。

EDIT1:回复@Grijesh 的评论

-128 和 +128 具有相同的表示形式:10000000。因此,为了避免混淆并制定规则All bit-patterns with 1 in higher-order bit represent negative numbers,决定将其视为 -128,这使得范围从 -128 到 127 而不是 -127.. +128。

【讨论】:

  • + 但我认为 OP 需要更多细节,你应该展示 2 的补码如何在一个字节中工作,-128 = 128 这就是127 + 1 给出-128 的原因。您可能会找到我给出的问题的链接答案。
  • @GrijeshChauhan 根据您的建议进行了编辑,并在该链接上也接受了我的 +1 :) 我之前避免了这个,因为问题不是关于为什么不是 -127 到 128?
【解决方案3】:

在二进制补码中,最左边的位是负数,其他位是正数,所以

1000 0000

=> -128

1000 0001

=> -128 + 1 = -127

因此最大的数字是 0111 1111 (127),最小的数字是 1000 0000 (-128)

【讨论】:

    【解决方案4】:

    您可以将signed datatypes 视为时钟。 12 小时后总是会打到 12 点。 Char 范围是 -128+127。所以当你根据我的时钟规则点击127时,下一次点击将是-128

    我建议你做一些二进制计算。

    更多信息请阅读http://en.wikipedia.org/wiki/Two%27s_complement

    【讨论】:

      【解决方案5】:

      在 c 中,char 是唯一的 1 字节内存分配意味着总共 8 位。 这是因为 8 位 2 的补码编码。带符号的字符范围是 -128 到 127。
      因为你用过。

         printf("%3d = %d\n", i, (signed char)i);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-06
        • 1970-01-01
        • 1970-01-01
        • 2020-08-09
        • 2014-05-28
        • 1970-01-01
        • 2013-07-19
        • 1970-01-01
        相关资源
        最近更新 更多