如何检查有符号整数是负数还是正数?

发布于 2024-09-28 15:57:33 字数 366 浏览 0 评论 0原文

我是 x86 汇编语言的新手,我在寄存器 eax 中保存了一个有符号整数,我想检查该数字是负数还是正数。为此,我使用 bt 指令来检查第一位。

这是我所做的:

bt eax,0
jnc isNegative

bt加载第一位进位标志,然后使用jnc检查进位标志是0还是1。

如果是1,则应该是负数,并执行负指令... 但是,输出是不可预测的,有时我有一个正数,它会将其识别为负数。我做错了什么吗?

编辑:我刚刚意识到这可能与位编号有关。它实际上是检查最低有效位而不是第一位。让我尝试使用 bt eax, 31

I am new to x86 assembly language, I have a signed integer saved in register eax, and I want to check if the number is negative or positive. To do that, I used bt instruction to check the first bit.

Here is what I did:

bt eax,0
jnc isNegative

bt loads the first bit to carry flag, and I used jnc to check if carry flag is 0 or 1.

If it's 1, it should be a negative number, and does negative instructions...
however, the output is unpredictable, sometimes I have a positive and it recognize it as a negative number. Am I doing something wrong?

EDIT: I just realized it could have something to do with bit numbering. It is actually checking the least significant bit instead of the first bit. Let me try using bt eax, 31

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

澜川若宁 2024-10-05 15:57:33

如果设置了 MSB,则该值为负数。 FLAGS 中的 SF(符号标志)根据结果的该位进行设置。

test eax, eax      ; set FLAGS according to the value in EAX; like cmp eax, 0
js   negative      ; jump if top bit was set in EAX

或者从 test reg,reg 设置FLAGS的方式与cmp reg,0相同,如果值为“less”,可以使用jl跳转比零”。这是同样的事情。有趣的事实:这也可以作为优化无符号 if(eax >= 0x80000000U) 的技巧。

您可以使用效率较低的指令(更长,因为它必须包含 32 位常量)手动将其作为一位测试(不利用 SF)。这很像您的 bt eax,31 但在设置符号位时设置 ZF=0 而不是 CF=1。

test eax, 0x80000000      ; set flags according to EAX & (1<<31)
jnz  negative             ; jump if that result was non-zero, i.e. bit was set

这适用于任何寄存器大小、字节 (int8_t)、字 (int16_t)、双字 (int32_t) 或 qword (int64_t)。例如,对于字节:

test al, al
js   is_negative
; or
test al, 80h
jne  is_negative

如果寄存器中的值是由“根据结果”设置 FLAGS 的内容生成的,就像大多数 ALU 指令一样,例如 添加ecx, edx,无需测试即可通过js查看是否为负数ecx,ecx 首先。 SF 已通过 add 指令根据 ECX 中值的 MSB 设置。


术语:正数不包括零

  • 正数是x > 0 。 1 或更大的数字,不包括零。 (有时宽松地用作负数的反义词,但严格来说不是。)
  • 非负数是 x >= 0
  • 负数是 x < 0 。
  • 零既不是正数也不是负数。其 2 的补码位模式全为零,没有设置任何位。 (x86 使用 2 的补码有符号整数,就像所有其他现代 CPU 一样。这就是为什么没有整数负零。)

因此,如果您想确定一个数字是正数还是负数,则需要进行两次单独的检查,除非您已经知道它非零。 (假设您使用积极的严格定义。有时,您可以从上下文推断某人表示一种条件,但精确的术语在计算中很有用,因此您最好自己使用。)


您的 bt 想法可以工作,但 x86 从底部的位 0(最低有效位)到位 31 进行编号,作为 32 位寄存器(如 EAX)的符号位。另外,CF 集表示负数,因此jc 负数。但 bt 并不更快,除非您确实希望进位标志中的条件与 adc edx, 0 一起使用来执行 negcount += (x<0) 计算负数什么的。另外,add eax,eaxshl eax,1 会将 EAX 的最高位移入 CF(并且还会修改 EAX,与 BT 不同)。

The value is negative if the MSB is set. The SF (sign flag) in FLAGS is set according to that bit of the result.

test eax, eax      ; set FLAGS according to the value in EAX; like cmp eax, 0
js   negative      ; jump if top bit was set in EAX

Alternatively since test reg,reg sets FLAGS the same way as cmp reg,0, you could use jl to jump if the value is "less than zero". That's the same thing. Fun fact: this also works as a trick for optimizing unsigned if(eax >= 0x80000000U).

You can manually do it as a single-bit test (not taking advantage of SF) with a less efficient instruction (longer because it has to include the 32-bit constant.) This is a lot like your bt eax,31 but setting ZF=0 instead of CF=1 when the sign bit is set.

test eax, 0x80000000      ; set flags according to EAX & (1<<31)
jnz  negative             ; jump if that result was non-zero, i.e. bit was set

This works for any register size, byte (int8_t), word (int16_t), dword (int32_t), or qword (int64_t). For example with bytes:

test al, al
js   is_negative
; or
test al, 80h
jne  is_negative

If the value in a register was produced by something that sets FLAGS "according to the result", like most ALU instructions such as add ecx, edx, you can js to see if it's negative or not without needing to test ecx, ecx first. SF is already set according to the MSB of the value in ECX, by the add instruction.


Terminology: positive doesn't include zero

  • positive is x > 0. Numbers 1 or greater, not including zero. (Sometimes used loosely as the opposite of negative, but strictly speaking it's not.)
  • non-negative is x >= 0.
  • negative is x < 0.
  • zero is not positive or negative. Its 2's complement bit-pattern is all-zero, no bits set. (x86 uses 2's complement signed integers, like all other modern CPUs. That's why there's no integer negative-zero.)

So if you want to find out if a number is positive or negative, that's two separate checks unless you already know it's non-zero. (Assuming you're using a strict definition of positive. Sometimes from context you can infer that someone means one condition, but precise terminology is useful in computing so prefer that yourself.)


Your bt idea could work, but x86 numbers bits from bit 0 at the bottom (least significant), to bit 31 as the sign-bit of a 32-bit register like EAX. Also, CF set means negative, so jc negative. But bt isn't faster unless you actually want the condition in the carry flag for use with adc edx, 0 to do negcount += (x<0) counting negative numbers or something. Alternatively, add eax,eax or shl eax,1 will shift the top bit of EAX into CF (and also modify EAX, unlike BT).

酒浓于脸红 2024-10-05 15:57:33

您可以使用jgecmp指令:

cmp eax, 0
jl isNegative

You can use the jge and cmp instructions:

cmp eax, 0
jl isNegative
入画浅相思 2024-10-05 15:57:33

您当前的解决方案检查数字是偶数还是奇数,而是测试第 31 位:

bt eax, 31
jc number_is_negative

或者您可以将数字与零进行比较,并测试它是否大于或等于它。

main:
    ...
    cmp eax, 0 ; Compare the number to zero
    jge .number_is_positive ; If it's positive jump to .number_is_positive
    ; And only arrive here if a number is negative
    ...
.number_is_positive:
    ; Yay! number is positive
    ...

Your current solution checks if the number is even or odd, instead test the 31st bit:

bt eax, 31
jc number_is_negative

Or you can compare the number to zero, and test whether it's greater than or equal to it.

main:
    ...
    cmp eax, 0 ; Compare the number to zero
    jge .number_is_positive ; If it's positive jump to .number_is_positive
    ; And only arrive here if a number is negative
    ...
.number_is_positive:
    ; Yay! number is positive
    ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文