在 TC++ 编译器中,5的二进制表示是(00000000000000101)。我知道负数存储为 2 的补码,因此二进制中的-5是(111111111111011)。最高有效位(符号位)是 1,表示它是负数。
那么编译器如何知道它是-5呢?如果我们将上面给出的二进制值(111111111111011)解释为无符号数,结果会完全不同吗?
另外,为什么 1 是5 -6 (1111111111111010)的补码?
在 TC++ 编译器中,5的二进制表示是(00000000000000101)。我知道负数存储为 2 的补码,因此二进制中的-5是(111111111111011)。最高有效位(符号位)是 1,表示它是负数。
那么编译器如何知道它是-5呢?如果我们将上面给出的二进制值(111111111111011)解释为无符号数,结果会完全不同吗?
另外,为什么 1 是5 -6 (1111111111111010)的补码?
编译器不知道。如果你投到-5
你unsigned int
会得到32763
.
编译器知道,因为这是 CPU 原生使用的约定。您的计算机有一个 CPU,它以二进制补码表示法存储负数,因此编译器也会效仿。如果您的 CPU 支持一个补码表示法,编译器将使用它(顺便说一下,IEEE 浮点数就是这种情况)。
有关该主题的 Wikipedia 文章解释了二进制补码符号的工作原理。
处理器实现有符号和无符号指令,它们将以不同的方式对二进制数表示进行操作。编译器根据所涉及的操作数的类型(即int
vs. unsigned int
)知道要发出哪些指令。
编译器不需要知道一个数字是否为负,它只是为所涉及的类型发出正确的机器或中间语言指令。这些指令的处理器或运行时的实现通常不太关心数字是否为负,因为二进制补码算法的公式对于正数或负数是相同的(事实上,这是主要的补码算法的优势)。需要知道一个数字是否为负数printf()
,就像 Andrew Jaffe 指出的那样,设置的 MSBit 表示二进制补码中的负数。
第一位仅为负数设置(称为符号位)
详细信息可在此处获得
二进制补码的kewl部分是机器语言加法和减法指令可以忽略所有这些,只做二进制算术,它就可以工作......
即,-3 + 4
在二进制 2 的补码中,是
1111 1111 1111 1101 (-3)
+ 0000 0000 0000 0100 ( 4)
-------------------
0000 0000 0000 0001 ( 1)
举个例子:我们在二进制的两个字节中有两个数字:A = 10010111 B = 00100110(注意机器不知道这个级别有符号或无符号的概念)
现在当您说“添加”这两个时,机器是什么?它只是添加:
R = 10111101(和进位位:1)
现在,我们——作为编译器——需要解释这个操作。我们有两个选择:数字可以有符号或无符号。
1-无符号情况:在c中,数字是“无符号字符”类型,值是151和38,结果是189。这是微不足道的。
2 - 带符号的情况:我们,编译器,根据它们的 msb 解释数字,第一个数字是 -105,第二个数字仍然是 38。所以 -105 + 38 = -67。但是 -67 是 10111101。但这就是我们在结果 (R) 中已有的内容!结果是一样的,唯一的区别是编译器如何解释它。
结论是,无论我们如何考虑数字,机器都会对数字进行相同的操作。但是编译器会依次解释结果。
请注意,不是机器知道 2 的补码的概念。它只是添加两个数字而不关心内容。然后,编译器查看符号位并决定.
When it comes to subtraction, this time again, the operation is unique: take 2's complement of the second number and add the two.
如果该数字被声明为有符号数据类型(而不是类型转换为无符号类型),那么编译器将知道,当符号位为 1 时,它是一个负数。至于为什么使用 2 的补码而不是 1 的补码,您不希望能够具有 -0 的值,而 1 的补码允许您这样做,所以他们发明了 2 的补码来解决这个问题。
这正是最重要的位——如果你知道一个数字是有符号的,那么如果 MSB=1 编译器(和运行时!)知道将其解释为负数。这就是为什么类 c 语言同时具有整数(正数和负数)和无符号整数的原因——在这种情况下,您将它们都解释为正数。因此,有符号字节从 -128 到 127,但无符号字节从 0 到 255。