算術右移 邏輯右移


先由一道題目引入:有兩個變量a和b,不用if、?:、switch等判斷語句,找出較大的那個變量。

其中一種答案如下:

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。

//c = c >> (sizeof(int) * 8 - 1);
004114F3  mov         eax,dword ptr [c] 
004114F6  sar         eax,1Fh 
004114F9  mov         dword ptr [c],eax 

 而有unsigned的話移位后則為0x00000001。

//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(邏輯右移)

 經驗證vc和gcc均默認為算術右移,上面的匯編代碼也說明了這一點,有unsigned時右移采用的是shr(shift logical right)邏輯右移,無unsigned時采用sar(shift arithmetic right)算術右移。

 《c和指針》中也建議不要對有符號數進行>>操作,所以為了確保結果一定,>>時把數值轉成unsigned

 又試了一下<<,發現signed和unsigned都是采用shl邏輯左移,應該是shl和sal效果都一樣,所以編譯器就統一采用shl。

 試驗int 0x80000000 << 1結果為0,說明符號位對左移沒影響。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM