如何在x86汇编中比较有符号值和无符号值

11

我在寻找一种比较x86汇编代码中正数和负数的方法。

例如:当我比较-1和1时,我总是得到-1比1更大的结果。我知道这是因为2的补码格式使得负数在底层二进制中比正数更大。

但是否有人可以提供一段x86汇编代码来正确地进行正负数比较(例如1>-1)?


1
一个变量不一定是无符号的。有符号和无符号的比较是相同的——它们的区别在于如何解释标志位。那么,你是如何解释这些标志位的呢? :) - 500 - Internal Server Error
你的标题说是无符号的,但在问题中你谈到了比较有符号的正数和负数。这是哪一个?你的输入中的最高位是否根本不是符号位,而只是无符号二进制位值?例如,在8位中,你想做类似于cmp(0xff, 0xff)的操作,将相同的位模式解释为一个操作数的255,而另一个操作数的-1?这就是比较无符号和有符号值所意味的,也是Alexis的答案所回答的。Pax的答案涵盖了仅在两个2的补码数字之间进行有符号比较的情况,无论其是否为正数。 - Peter Cordes
2个回答

18

可能在使用以下其中一种未签名的变量,例如:

cmp  eax, ebx
jb   lesser

对于检查有符号数之间的等价物,例如:

cmp  eax, ebx
jl   lesser

这个链接提供了有关跳转变体的很好的概述,包括它们的符号和它们检查的标志,这里部分内容是复制的:

Instruction  Jump if ...           Signed?   Flags
-----------  -----------           --------  -----
JO           overflow                        OF=1
JNO          not overflow                    OF=0
JS           sign                            SF=1
JNS          not sign                        SF=0
JE/JZ        equal
             zero                            ZF=1
JNE/JNZ      not-equal
             not-zero                        ZF=0
JB/JNAE/JC   below
             not-above-or-equal
             carry                 unsigned  CF=1
JNB/JAE/JNC  not-below
             above-or-equal
             no-carry              unsigned  CF=0
JBE/JNA      below-or-equal
             not-above             unsigned  CF=1 or ZF=1
JA/JNBE      above
             not-below-or-equal    unsigned  CF=0 and ZF=0
JL/JNGE      less
             not-greater-or-equal  signed    SF<>OF
JGE/JNL      greater-or-equal
             not-less              signed    SF=OF
JLE/JNG      less-or-equal
             not-greater           signed    ZF=1 or SF<>OF
JG/JNLE      greater
             not-less-or-equal     signed    ZF=0 and SF=OF
JP/JPE       parity
             parity-even                     PF=1
JNP/JPO      not-parity
             parity-odd                      PF=0
JCXZ/JECXZ   CX register is zero
             ECX register is zero

3

两个符号不同的数字不能直接进行比较。实际上大多数软件语言都有这个规则。C和C++在其文档中具体提到了这一点,并且在您在同一表达式中使用有符号和无符号整数时,通常会生成警告,这可能导致未知的符号。

唯一的方法是首先检查有符号数是否为负数,如果是,则知道它比另一个数字小。然后您可以将这两个数字作为无符号整数进行比较。

; is eax < ebx (eax signed, ebx unsigned)

cmp eax, $0
jl less

cmp eax, ebx
jc less

顺便提一下:如果两个数字的大小都小于处理器支持的最大大小,那么显然可以比较它们是否带符号。在这种情况下,您需要适当地扩展有符号和无符号位,然后就可以像两个有符号值一样进行比较。

假设您想要比较两个字节 al 和 bl,则可以使用以下代码:

movsx ax, al
xor bh, bh    ; or movzx bx, bl
cmp ax, bx
jl less

(注意,我不保证jl是正确的,它可能是jle或jnl...)

1
在32位模式下,movsx eax, al / movzx ebx, bl 是最有效的方法。(在现代x86的16位模式下也是如此,以避免错误依赖)。无论如何,除非您需要代码在pre-386上运行,否则在大多数CPU上,movzx bx, bl比写BH然后读取BX更好。 - Peter Cordes

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