Linux C 编程教程第 15 部分 - 2s 补数和负数
在此页
- 2s补码
- 负数
- 结论
到目前为止,在这个正在进行的 C 编程教程系列中,我们已经讨论了很多概念,但遗漏了一个基本概念。它是关于负数的。是的,虽然我们在我们的一个初始教程中简要提到了有符号变量和无符号变量,但我们实际上并没有讨论负数是如何存储在内存中的。
好吧,这正是本教程将要讨论的内容。因此,废话不多说,让我们开始讨论。
2s补码
在我们开始解释内存中的负数表示之前,重要的是我们知道 1 和 2 补码的概念,它们都是二进制级别的操作。
让我们举一个非常简单的例子。假设你有一个 4 字节整数 a,十进制值为 15。那么它在二进制形式内存中的表示方式如下:
00000000 00000000 00000000 00001111
现在,要计算补码,只需反转所有位即可。所以下面是 15 的 1s 补码表示:
11111111 11111111 11111111 11110000
现在,如果将 1 加到上面的二进制表示中,就会得到 2 的补码。
11111111 11111111 11111111 11110001
所以上面的表示是15的二进制补码。
负数
现在,你们中的一些人一定在想为什么我们要讨论 1 和 2 的补码?好吧,答案在于负数的二进制表示是通过 2s 补码计算的。
难以置信?这是证明:
我们在上一节中计算的2s补码可以用十六进制表示为0xFFFFFFF1。现在,让我们通过 C 程序看看这个值的十进制形式是什么
继承人的代码:
#include <stdio.h>
int main()
{
int a = 0xFFFFFFF1;
printf("a = %d", a);
return 0;
}
以下是输出:
a = -15
现在相信了吗?我们从一个数字 15 开始,计算它的 2s 补码,当我们再次将二进制补码值转换为十进制时,我们发现它是 -15。
继续,现在让我们稍微调整代码以确保 printf 调用读取变量 a
#include <stdio.h>
int main()
{
int a = 0xFFFFFFF1;
printf("a = %u", a);
return 0;
}
现在是输出:
a = 4294967281
糟糕,输出改变了,现在它是一个巨大的正值。但是为什么会这样呢? 0xFFFFFFF1 不是我们之前看到的 15 的 2s 补码吗?
是的,0xFFFFFFF1 是 15 的补码,但如果不从那个角度看,它也是一个正常值(4294967281)。不同之处在于它的阅读方式。如果它作为有符号整数读取(通过 printf 中的 %d),您将看到输出为 -15,但如果它作为无符号整数读取(通过 printf 中的 %u),您将看到输出为 4294967281。
作为带符号变量(处理负值和正值)的经验法则,请记住,负数的二进制表示始终将 1 作为最左边的位,而在正数的情况下,所讨论的位始终为 0。
最后,请注意,您还可以反转二进制补码表示以获得其正对应物。作为示例,我们再次使用 0xFFFFFFF1 值,它是 -15 的十六进制表示。它以二进制形式表示为:
11111111 11111111 11111111 11110001
现在,要获得它的正对应物,只需再次执行 2s 补码。这意味着,首先进行 1s 补码:
00000000 00000000 00000000 00001110
然后加1
00000000 00000000 00000000 00001111
现在,如果你转换它,你将得到十进制形式的值 15。
结论
我希望本教程帮助您了解负数在内存中的表示方式的概念。我建议您尝试我们在本教程中使用的示例,如果您遇到任何问题,或者您有任何疑问或疑问,请在下面给我们留言。