负数在内存中以二进制补码的形式存储,那么CPU如何知道它是正数还是负数?

24

-1可以用4位二进制数(2's complement) 1111来表示。

15也被表示为1111。

那么,当CPU从内存中获取数值时,它如何区分15和-1呢?

5个回答

20

当CPU把一个字节从一个位置移动到另一个位置时,它并不关心这个字节是否为-1或15。不存在“有符号移动”(对于相同大小的目标位置没有有符号移动 - 对于更大或更小的目标位置有有符号移动)。

CPU只在对字节进行算术运算时才关心其表示方式。根据您选择的操作码(或代表您选择的编译器),CPU知道是否执行有符号或无符号算术运算。


有符号和无符号算术只在1s补码的情况下才有影响。在2的补码中,符号是自明的。 - Amal Antony
11111111b + 00000001b,@amalantony:如果两个量都是无符号的(假设是8位寄存器),则会发生溢出。如果它们是有符号的,则不会溢出。如果编译器没有关于类型的信息(例如在操作码或某些标志中)则无法区分它们之间的差异。 - Mat
@Peter 系统是如何决定 15(1111b)-1=14 和 -1(1111b)-1(0001b)=-2 的呢? - MCG
@amal:在二进制补码表示中,有符号和无符号确实有所不同。例如,指令集可能会为有符号和无符号比较提供单独的操作码。而C编译器将根据操作数的C类型(有符号 vs 无符号)发出相应的比较指令。 - Jim Lewis
@MCG:这将是一个糟糕的例子,因为1111b - 0001b = 1110b,可以正确地解释为无符号(15-1=14)或有符号(-1-1=-2)。然而,乘法和除法需要针对有符号和无符号使用不同的指令。 - Elliot Nelson
@JimLewis:我从编译器的角度回答了原始问题。我认为MCG想知道在二进制补码形式下,15和-1的表示方式有何不同。当涉及到CPU时,一切都归结于生成的操作码类型,就像Peter和你提到的那样。 - Amal Antony

10

大部分之前的答案提到了不同的操作码。对于更复杂的操作,如乘法和除法,这可能是正确的,但对于简单的加减法,CPU 的工作方式并非如此。

CPU 在其标志寄存器中保存有关指令结果的数据。在 x86(我最熟悉的)上,这里最重要的两个标志是“溢出”和“进位”标志。

基本上,CPU 不关心数字是有符号还是无符号,它们都被视为相同。当数字超过它所能包含的最高无符号值时,设置进位标志。当它超过或低于无符号数字的范围时,设置溢出标志。如果您使用无符号数字,则检查进位标志并忽略溢出标志。如果您使用带符号数字,则检查溢出标志并忽略进位标志。

以下是一些示例:

无符号:

1111(15)+ 1111(15)= 1110(14)

现在要做的是检查进位标志,在这种情况下该标志包含一个给出最终结果的值。

1 1110(30)

有符号:

1111(-1)+ 1111(-1)= 1110(-2)

在这种情况下,忽略进位标志,溢出标志应设置为零。

无符号:

0111(7)+ 0111(7)= 1110(14)

当您检查进位标志时,它应该为零。

有符号:

0111(7)+ 0111(7)= 1110(-2)

在这种情况下,将设置溢出标志,表示加法存在错误。

因此,总之,数字仅基于您对其的解释而有符号或无符号。 CPU 为您提供了区分它们所必需的工具,但不会自动进行区分。


7
CPU并不知道一个数字是有符号还是无符号的。当编译器创建机器语言文件时,它会选择正确的操作来执行与该数字的数学运算。例如,如果您声明变量为有符号类型,则在机器语言中执行的操作将是将该内存位置视为有符号值的操作。
在任何软件中,只有在解释数据时才能赋予其意义。内存中的一个字节可以是有符号或无符号数字、字符、音乐文件的一部分、图片中的像素等等。赋予其意义的是您如何使用该字节。

2

在编译器层面,区分是基于数据类型的。如果数据类型是int,在C语言中,那么将分配4个字节给该变量。所以,2的补码中的15是00000000 00000000 00000000 00000000 00001111,而-1是11111111 11111111 11111111 11111111。编译器然后将其转换为CPU的相应操作码。CPU执行这个操作码,在这个层面上,一切都是以1和0的形式存在的。


6
那并没有回答问题,问题是CPU如何起作用。 CPU不懂C语言。 - Mat
编译器为每个数字分配预定义的字节数(不考虑语言,C只是一个例子)。如果二进制版本由所有1组成,则为-1;如果至少有一个前导0位,则被解释为非零整数值。你明白了吗? - Amal Antony
不是这个问题。问题是:假设我有 unsigned char i=255;,它的二进制表示为 11111111。如果使用有符号字符,则 11111111 表示 -127。CPU 无法从语言中获取类型信息。那么它如何知道哪个是哪个?(我并不是说这个问题实际上是可以回答的,因为它完全取决于实际的 CPU/指令集,只是说你的答案并没有回答这个问题。) - Mat
@amal 当它是一个4位机器时会发生什么? - MCG
@amalantony: _CPU看不到高级语言中定义的类型。_编译器必须以这样的方式发出其代码,以便CPU知道存储了什么类型的值以及它们需要什么类型的操作(有符号或无符号)。这将回答这个问题。 - Mat
显示剩余3条评论

0
在二进制补码中,要表示15,我们需要5位。2的补码范围是-16到15,因此该值变为01111。这里最高位(MSB)是0,所以它是正数。对于-1,它将变为11111。

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