考虑此C函数;
int triangle(int width, int height)
{
return (width * height) / 2;
}
使用gcc(gcc -m32 -g -c test.c
)编译时,会产生以下汇编(objdump -d -M intel -S test.o
)。
test.o: file format elf32-i386
Disassembly of section .text:
00000000 <triangle>:
int triangle(int width, int height)
{
0: 55 push ebp
1: 89 e5 mov ebp,esp
return (width * height) / 2;
3: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
6: 0f af 45 0c imul eax,DWORD PTR [ebp+0xc]
a: 89 c2 mov edx,eax
c: c1 ea 1f shr edx,0x1f
f: 01 d0 add eax,edx
11: d1 f8 sar eax,1
13: 5d pop ebp
14: c3 ret
我已经知道,将整数n位右移会将其除以2 ^ n。但是,根据上述输出,有符号整数似乎被区别对待(这当然是有道理的)。如果我正确地读取了汇编输出,则在移位之前先将整数的符号位加进自己。
在右移之前将整数的符号位添加到自身的目的是什么?
答案 0 :(得分:2)
对于负数,它将获得正确的“向零舍入”结果。通过将舍入运算移向负无穷大,可以使负数与C除法运算符的预期结果产生不同的结果。
一个例子是-1:向右移动1仍给出-1,但是C运算符/ 2
给出0。
因此,额外的代码是对此效果的更正。如果不需要,请使用无符号或显式移位(但第二个选项的移植性较差)。