先由一道题目引入:有两个变量a和b,不用if、?:、switch等判断语句,找出较大的那个变量。html
其中一种答案以下:spa
1
2
3
4
|
char
* result[] = {
"a is larger"
,
"b is larger"
};
int
c = a - b;
c = unsigned(c) >> (
sizeof
(
int
) * 8 - 1);
cout << result[c] << endl;
|
sizeof(int) * 8 很好理解,就是求出int型占内存的bit数,-1就是为了右移后保留最高位,即保留符号位。指针
问题来了:为何移位时要把c转为unsigned呢?而一旦去掉unsigned关键字的话运行出错。调试
在vc2008中设置断点,调试,进入反汇编,发现问题出如今 >> 时,若是c为-1,则EAX(32位寄存器) = 0xffffffff,没有unsigned状况下移位后仍是0xffffffff。code
//c = c >> (sizeof(int) * 8 - 1);
004114F3 mov eax,dword ptr [c]
004114F6 sar eax,1Fh
004114F9 mov dword ptr [c],eax
|
而有unsigned的话移位后则为0x00000001。htm
//c = unsigned(c) >> (sizeof(int) * 8 - 1);
004114F3 mov eax,dword ptr [c]
004114F6 shr eax,1Fh
004114F9 mov dword ptr [c],eax
|
c右移的规则是:无符号数右移时左边高位移入0;有符号数右移时:1.符号位为0,移入0;2.符号位为1,有的系统移入1(算术右移),有的系统移入0(逻辑右移)。blog
经验证vc和gcc均默认为算术右移,上面的汇编代码也说明了这一点,有unsigned时右移采用的是shr(shift logical right)逻辑右移,无unsigned时采用sar(shift arithmetic right)算术右移。内存
《c和指针》中也建议不要对有符号数进行>>操做,因此为了确保结果必定,>>时把数值转成unsigned。ci
又试了一下<<,发现signed和unsigned都是采用shl逻辑左移,应该是shl和sal效果都同样,因此编译器就统一采用shl。get
试验int 0x80000000 << 1结果为0,说明符号位对左移没影响。