先由一道題目引入:有兩個變量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,說明符號位對左移沒影響。