会对一对有符号和无符号数进行算术运算是否合法?

时间:2011-01-10 09:22:00

标签: assembly integer math unsigned signed

我已经超过学习汇编的一半了,我熟悉有符号和无符号整数如何以位形式呈现的概念,我知道这似乎是一个奇怪的问题,答案是非常明显的,但是我想知道如果使用像加法这样的算术运算对于一对数字是有意义的,其中一个被认为是有符号而另一个是无符号的,我想到了下面的多个例子会产生正确的结果:

10000001(1字节整数,视为无符号,相当于129)
+
11111111(1字节整数并考虑有符号(二进制补码系统),相当于-1)


10000000(1字节整数,无符号逻辑,相当于128)

现在,如果上限值在AL寄存器中,并且我们有以下指令代码(采用GAS格式):

addb -1, %al

然后EFLAGS寄存器的进位标志(CF)将在操作完成后设置,并将通知实际上没有发生的溢出,并且可能因为溢出标志(OF)存在一个无符号数字应参考EFLAGS寄存器。所以,如果做这样的事情是明智的,我会很困惑。

5 个答案:

答案 0 :(得分:6)

在数学上,您不添加有符号或无符号数字。只有模2 32 的值(假设您有32位寄存器)。这些值涵盖了2个 32 连续整数的范围,但您可以自由地将该范围解释为几乎在任何地方开始。 “签名”和“未签名”只是两种解释。

换句话说,对于4位寄存器,“1011”的无符号解释是11,而带符号的解释是-5。但是只有一个值(数学家通常称之为“十一个模2 4 ”,因为数学家传统上喜欢无符号解释)。例如,如果你将“0110”添加到该值(在有符号和无符号解释中都是“六”),那么你得到“0001”,这是正确的值:减去五加六得一,十一加6是17,当减少模2 4 时(17是1加16;“减模2 4 ”大约除以16 [即2] sup> 4 ]并仅保留其余部分。

另一种说法如下:数值的(二进制)数字在概念上是无穷大的。 CPU寄存器仅保留最右边的32位。无符号解释是关于通常假设所有最左边的比特都为零。有符号的解释是关于通常假设所有最左边的比特具有与比特31相同的值(即,全部为零,或者全部为1)。无论哪种方式,当您执行加法(或减法或乘法)时,进位从右向左传播,而不是相反的传播,因此这些被忽略的位的值对32位结果没有任何影响。因此,只有一个“添加”操作码,它对程序员的大脑中的“操作数”是否“签名”或“未签名”无关紧要。

执行与模数算术兼容的操作时,必须考虑签名。转换成用于显示的十进制数字序列就是这样的操作。然而,更常见的情况是比较。模数为2 32 的值不是有序的;它们处于一种循环循环中(当你加上1到2 32 -1,并且减去modulo 2 32 时,你会回到0)。只有在整个整数范围内考虑整数时,比较才有意义。此时,您必须决定是使用签名还是未签名的解释。这就是为什么x86处理器同时提供jg(如果更大则跳转,签名解释)和ja(如果超过,则跳转,无符号解释)。

答案 1 :(得分:3)

数字或操作是签名还是无符号只是解释的问题。当你进行添加时会发生的事情是,两个数字被加在一起,使10000000在进位标志中带有1(因为它“离开了前端”)。然后由你的后续操作来解释这意味着什么(如果你在其他地方使用它,就像你将操作视为无符号添加而不包装;如果你把它扔掉,就像你在做签名一样加)。

答案 2 :(得分:3)

在二进制级别,只有一个加法操作:

 0101 + (5)
 1010 = (unsigned 10 or signed -6)
--------
 1111   (unsigned 15 or signed -1)

进位和溢出标志如何,它们都是根据一个简单的规则设置的。 CF可用于检测oveflow iff 我们认为操作数是无符号的,OF用于检测oveflow iff 我们认为它们都是有符号的。这两个标志都是根据结果设置的,由你来决定使用它们。

OF标志的实际公式是

OF = CF xor MSB_of_result.

这意味着如果我们添加两个正数(我们认为已签名),那么如果结果为负数,那么它就会过度消耗。

答案 3 :(得分:1)

“已签名”和“未签名”是解释。汇编指令通常会记录解释。我不知道有任何架构,其中有一个ADD-SIGNED-UNSIGNED指令将其中一个参数解释为有符号值,另一个解释为无符号值。它似乎也没什么价值。使用2s补码整数运算,唯一的区别在于一些标志寄存器。

答案 4 :(得分:1)

我发现这个非常好的 article 是我主要担心的问题,阅读完文章后答案很明确。