ARM处理器如何区分负数和正数?

Kav*_*avi -1 c embedded arm processor firmware

让我们考虑一个8位处理器来简化我的问题。我知道-2被存储为其2的补码,即0b1111_1110,该数据块的小数表示为254,对吗?现在,我的问题是,由于ARM处理器的二进制表示形式相同,因此它们将如何区分“ -2”和“ 254”?

我尝试查找整个互联网,每个人都在不断解释处理器如何存储负数。我需要知道的是它们是如何区分的。

use*_*733 7

-2以2的补码形式存储,即0b1111_1110,该数据块的十进制表示形式为254,对吗?

是的,对于典型的现代系统来说确实如此。

现在,我的问题是,由于ARM处理器的二进制表示形式相同,因此它们将如何区分“ -2”和“ 254”?

处理器没有;编译器可以。

假设您有表达value > 0。变量value和常量0都有一个类型。根据这些类型,编译器选择要使用的CPU指令。因此,有符号和无符号比较可能导致不同的编译器输出。

处理器不知道代码中的类型。它只是执行这些选定的指令。

ARM64 gcc的示例

int icmp(int num) {
    return num > 0;
}

int ucmp(unsigned int num) {
    return num > 0;
}
Run Code Online (Sandbox Code Playgroud)
icmp:
        sub     sp, sp, #16
        str     w0, [sp, 12]
        ldr     w0, [sp, 12]
        cmp     w0, 0
        cset    w0, gt
        and     w0, w0, 255
        add     sp, sp, 16
        ret
ucmp:
        sub     sp, sp, #16
        str     w0, [sp, 12]
        ldr     w0, [sp, 12]
        cmp     w0, 0
        cset    w0, ne
        and     w0, w0, 255
        add     sp, sp, 16
        ret
Run Code Online (Sandbox Code Playgroud)

查看编译器如何生成略有不同的cset指令。


Gil*_*il' 5

大多数处理器(包括 Arm 处理器)不区分有符号数和无符号数。包含 0b1111_1110 的字节可以解释为值为 254 的无符号整数或值为 -2 的有符号整数。或者它可以被解释为其他东西,比如浮点数、定点数、字符等。决定这种解释的是你对其进行的操作。

对于许多指令来说,值是有符号整数还是无符号整数并不重要:有符号整数的表示形式旨在通过对字大小取模来使它们变得轻量级。例如,将两个相同大小的值相加只是一条add指令;这些值是否有符号并不重要。

对于某些指令,处理器提供不同的指令。例如,有两组指令用于将值复制到更大的寄存器:SXTB(符号扩展字节)及其朋友,以及UXTB(零扩展字节)及其朋友。UXT* 指令将值复制到目标寄存器的低位,并将高位设置为零。SXT* 指令将值复制到目标寄存器的低位,并将高位设置为该值的高位,即它们将此高位解释为符号位。

从 C 的角度来看,编译器的工作是根据操作数使用正确的指令。例如,如果编译器看到

uint8_t x = 0xfe;
uint32_t y = x + 3;
Run Code Online (Sandbox Code Playgroud)

它决定最好的编译方法是将其存储x在 32 位寄存器的低位中,并且y作为另一个 32 位寄存器,它将发出一条 UXTB 指令来设置寄存器,y然后发出0x000000fe一条ADD指令来获取的期望值x。(当然,在实践中,这个片段将被优化掉。)