算術移位和邏輯移位實現分析


參考:http://blog.sina.com.cn/s/blog_944790400101bsi8.html

        http://www.feiesoft.com/asm/05-2-05.html

unsigned int i = 8;
int main()
{
     i = i<<3;//輸出結果i = 64
}
請問:上面的變量i是采用邏輯移位還是算術移位呢?
邏輯移位,簡單理解就是物理上按位進行的左右移動,兩頭用0進行補充,不關心數值的符號問題。
算術移位,同樣也是物理上按位進行的左右移動,兩頭用0進行補充,但必須確保符號位不改變。

算術移位指令

算術移位指令有:算術左移SAL(ShiftAlgebraic Left)和算術右移SAR(ShiftAlgebraic Right)。它們的指令格式如下:SAL/SAR Reg/Mem, CL/Imm,受影響的標志位:CF、OF、PF、SF和ZF(AF無定義)。算術移位指令的功能描述如下:

(1)算術左移SAL把目的操作數的低位向高位移,空出的低位補0;

      

(2)算術右移SAR把目的操作數的高位向低位移,空出的高位用最高位(符號位)填補。

      

邏輯移位指令

此組指令有:邏輯左移SHL(ShiftLogical Left)和邏輯右移SHR(ShiftLogical Right)。它們的指令格式如下:SHL/SHR Reg/Mem, CL/Imm,受影響的標志位:CF、OF、PF、SF和ZF(AF無定義)。邏輯左移/右移指令只有它們的移位方向不同,移位后空出的位都補0

(1)邏輯左移SHL 

(2)邏輯右移SHR 

但我們好奇的是“i<<3”和“i>>3”到底采用的是算術還是邏輯移位呢?其實單從C語言本身來看可能沒有太多突破,

因為C最終會被編譯器編譯成目標平台的匯編代碼,所以必須要結合編譯器和匯編程序來分析以上代碼。

在vc6.0中,按F9可以設置一個斷點,然后調試運行,點擊Disassembly

也可以,直接調試運行時,在斷點處右鍵,點擊Go to Disassembly,顯示匯編代碼。

即可顯示匯編代碼

以下幾種情況:

(1)當i是無符號整形時,向左移動3位,采用的是邏輯左移。

unsigned int i = 8; i = i<<3;//輸出結果i = 64

(2)當i是有符號整形時,向左移動3位,采用的也是是邏輯左移。

int i = 8;
i = i<<3;//輸出結果i = 64

結論:不管是否有無符號類型,也不管值的正負,均采用的是邏輯左移。

 (3)當i是無符號整形時,向右移動3位,采用的也是是邏輯右移。

unsigned int i = 8;
int main()
{
    i = i>>3;//輸出結果i = 1
}

(4)當i是有符號整形時,向右移動3位,采用的是算術右移。

int i = 8;
int main()
{
    i = i>>3;//輸出結果i = 1
    return 0;
}

(5)負數時,當把unsigned int i = -8時(在32位window系統下),右移動三位:

(6)當int i=-8時,右移動三位,結果多少呢?結果是-1

結論:說明只要是有符號數,不管值是正還是負,右移時采用的都是算術右移。

疑問:按照移位補0的原則,為何左移都是邏輯移位呢?
答疑:先看看“-8”和“8”在計算機內存中的值分別是:
0xfffffff8
0x8
由於計算機均按補碼保存數值,所以不管符號正負,左移對於符號位並不產生影響,而右移則就不同了,無符號數怎么右移都不影響符號位,但是有符號數邏輯右移時高位補0將改變符號位,所以只能采用算術右移。
 
總結:只有有符號數右移才采用算術右移,否則其它情況都采用邏輯移位操作(邏輯左移或邏輯右移)。原來只要明白計算機是以補碼方式保存數值的,就一切都清楚了。

 

 

 


免責聲明!

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



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