编译器如何将无符号整数打印为有符号整数?

3

我正在尝试弄清楚以下代码的原因:

{
  unsigned int a = 10;
  a = ~a;
  printf("%d\n", a);
}

a 最初将是 00001010,经过 NOT 操作后,将会转换为

11110101

当尝试将 a 作为有符号整数打印时,究竟发生了什么,导致打印结果为 -11

我以为可能会看到 -5(根据二进制表示),但不会是 -11

我很乐意在此问题上得到澄清。

2个回答

6

使用2的补码表示法来存储负数。

数字10在4字节二进制中为0000 0000 0000 0000 0000 0000 0000 1010。

a=~a将a的内容变为1111 1111 1111 1111 1111 1111 1111 0101。

当将该数字视为有符号整数时,编译器会将最高位作为符号位,其余位作为大小。

最高位的1使该数字成为负数。

因此,在剩余的位上执行2的补码运算。

因此,111 1111 1111 1111 1111 1111 1111 0101变为000 0000 0000 0000 0000 0000 0000 1011。

这被解释为一个十进制整数为-11。


1
严谨的注释:C语言不要求使用二进制补码。它甚至没有规定数字的存储方式。但是,x86和ARM处理器使用二进制补码。 - Cole Tobin

2
当您编写 a = ~a; 时,您将翻转 a 中的每个位,也称为按位取反。
负数的表示被声明为“实现相关”,这意味着不同的架构可以对 -10-11 有不同的表示方式。
假设在一个使用补码表示负数的常见处理器上使用32位架构,那么-1将被表示为 FFFFFFFF(十六进制)或32位都是1。 ~a 将被表示为 = FFFFFFF5 或二进制 1...10101,这是表示-11的方式。
备注:第一部分始终相同且不受实现相关影响,~a 在任何32位架构上都是 FFFFFFF5。只有第二部分(-11 == FFFFFFF5)是实现相关的。顺便说一下,在使用补码表示负数的架构中,它将是-10。

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