amj*_*jad 1 c assembly unsigned
我在看一本教科书,上面写着:
重要的是要注意机器代码如何区分有符号和无符号值。与 C 不同,它不将数据类型与每个程序值相关联。相反,它主要对这两种情况使用相同的(汇编)指令,因为许多算术运算对于无符号和补码算术具有相同的位级行为。
我不明白这是什么意思,谁能给我举个例子?
例如,这段代码:
int main() {
int i = -1;
if(i < 9)
i++;
unsigned u = -1; // Wraps around to UINT_MAX value
if(u < 9)
u++;
}
Run Code Online (Sandbox Code Playgroud)
在 x86 GCC 上给出以下输出:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], -1 ; i = -1
cmp DWORD PTR [rbp-4], 8 ; i comparison
jg .L2 ; i comparison
add DWORD PTR [rbp-4], 1 ; i addition
.L2:
mov DWORD PTR [rbp-8], -1 ; u = -1
cmp DWORD PTR [rbp-8], 8 ; u comparison
ja .L3 ; u comparison
add DWORD PTR [rbp-8], 1 ; u addition
.L3:
mov eax, 0
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
请注意它如何对变量和使用相同的初始化 ( mov) 和增量 ( add)指令。这是因为无符号和 2 的补码的位模式变化相同。iu
比较也使用相同的指令cmp,但跳转决定必须不同,因为设置最高位的值在类型上是不同的:(jg如果更大则跳转)在有符号上,ja(如果大于则跳转)在无符号上。
选择什么指令取决于体系结构和编译器。
在 Intel 处理器(x86 系列)和其他具有 的处理器上FLAGS,您可以从那些FLAGS告诉您最后一个操作如何工作的位中获得信息。处理器之间的名称FLAGS略有不同,但一般来说,在算术方面有两个重要的名称:CF和OF。
CF是进位位(通常C在其他处理器上称为)。
OF是溢出位(通常V在其他处理器上称为)。
或多或少,CF代表无符号溢出,OF代表有符号溢出。当处理器执行ADD操作时,它有一位额外的位,即CF。因此,如果将两个 64 位数字相加,则未换行的结果可能需要 65 位。这就是进位。该OF标志被设置为最高位(即 64 位数字中的位 63),对两个源和目标中的该位使用 3 个逻辑运算。
有一个关于如何CF使用 4 位寄存器的示例:
R1 = 1010
R2 = 1101
R3 = R1 + R2 = 1 0111
^
+---- carry (CF)
Run Code Online (Sandbox Code Playgroud)
额外的部分1不适合 R3,因此它被放入位中CF。附带说明一下,MIPS 处理器没有任何FLAGS. 由您决定是否生成进位(您可以在两个源和目标上使用 XOR 等来执行此操作)。
但是,在 C(和 C++)中,没有验证整数类型的溢出(至少默认情况下没有)。因此,换句话说,除了CF四个OF比较运算符(<、<=、>、>=)。
如@user694733 提供的示例所示,区别在于是否使用ajg或。ja16条跳转指令中的每一条都会测试各种标志来判断是否跳转。这种组合确实是与众不同的。
ADC另一个有趣的方面是和之间的区别ADD。在一种情况下,您需要添加进位,而另一种情况则不添加。现在我们有 64 位计算机,它可能不会被广泛使用,但是要使用 32 位处理器添加两个 64 位数字,它将把低 32 位添加为无符号 32 位数字,然后添加高 32 位数字(有符号或无符号(视情况而定)加上第一次操作的进位。
假设 32 位寄存器中有两个 64 位数字 (ECX:EAX和EDX:EBX),您可以像这样添加它们:
ADD EAX, EBX
ADC ECX, EDX
Run Code Online (Sandbox Code Playgroud)
这里,如果有无符号溢出EDX,则将 和 进位相加(进位——意味着现在应该用33位来表示 和 ,因为结果不适合 32 位,标志是第 33 位)。ECXEAX + EBXEAXEBX CF
需要注意的是,英特尔处理器具有:
ZF无论结果是否为零,)CFSBC减去 (for , SBB,)时称为“借位”并且AF用于“十进制数运算”的位(头脑清醒的人不会使用它。)该AF位告诉您十进制运算中存在溢出。类似的事情。我从来没有用过那个。我发现它们的使用太复杂/麻烦。此外,该位在 amd64 中仍然存在,但设置它的指令已被删除(参见DAA示例)。