在嵌入式開發中,移位操作是常用的一種運算。但是在進行移位運算的時候,如果沒有考慮到有符號和無符號的移位區別,就很容易掉進陷阱,得不到我們想要的結果。
我們可以看下面例子,你們猜出結果麼?
signed
char
i = -125;
i= i >> 2;
cout
<<
(int
)i;return
0;編譯結果為:-32
為什麼有這樣的結果?首先介紹兩個概念:邏輯移位和算數移位。
邏輯移位,簡單理解就是物理上按位進行的左右移動,兩頭用
0進行補充,不關心數值的符號問題。
算術移位,同樣也是物理上按位進行的左右移動,兩頭用
0進行補充,但必須確保符號位不改變。
算術移位指令
算術移位指令有:算術左移
sal(shiftalgebraic left)
和算術右移
sar(shiftalgebraic right)
。算術移位指令的功能描述如下:(1
)算術左移
sal把目的運算元的低位向高位移,空出的低位補0;
)算術右移
sar把目的運算元的高位向低位移,空出的高位用最高位
(符號位
)填補。
邏輯移位指令
此組指令有:邏輯左移
shl(shiftlogical left)
和邏輯右移
shr(shiftlogical right)
。邏輯左移
/右移指令只有它們的移位方向不同,移位後空出的位都補0。
(1)
邏輯左移
shl
(2)
邏輯右移
shr
但我們好奇的是
「i<<3」
和「i>>3」
到底採用的是算術還是邏輯移位呢?其實單從
c語言本身來看可能沒有太多突破,因為c
最終會被編譯器編譯成目標平台的彙編**,所以必須要結合編譯器和匯程式設計序來分析以上**。
在vs 2015
中,按f9
可以設定乙個斷點,然後除錯執行,快捷鍵
ctrl+alt+d
進入反彙編。(本科痛苦的半個月學習的彙編,總還是用上了,嘚瑟)。
以下幾種情況:(1
)當i是無符號整形時,向左移動
3位,採用的是邏輯左移。
unsigned int i = 8;
i = i<<3;//
輸出結果i = 64
)當i是有符號整形時,向左移動
3位,採用的也是是邏輯左移。
int i = 8;
i = i<<3;//
輸出結果i = 64
結論:不管是否有無符號型別,也不管值的正負,均採用的是邏輯左移。(3
)當i是無符號整形時,向右移動
3位,採用的也是是邏輯右移。
)當i是有符號整形時,向右移動
3位,採用的是算術右移。
)負數時,當把
unsigned int i =-8時(
在32位window
系統下)
,右移動三位:
)當int i=-8
時,右移動三位,結果多少呢?結果是
結論:說明只要是有符號數,不管值是正還是負,右移時採用的都是算術右移。
疑問:按照移位補
0的原則,為何左移都是邏輯移位呢?
答疑:先看看「-
8」和「8」在計算機記憶體中的值分別是:
0xfffffff8
0x8由於計算機均按補碼儲存數值,所以不管符號正負,左移對於符號位並不產生影響,而右移則就不同了,無符號數怎麼右移都不影響符號位,但是有符號數邏輯右移時高位補
0將改變符號位,所以只能採用算術右移。
總結:只有有符號數右移才採用算術右移,否則其它情況都採用邏輯移位操作
(邏輯左移或邏輯右移
)。原來只要明白計算機是以補碼方式儲存數值的,就一切都清楚了。
c語言中的左移和右移
先說左移,左移就是把乙個數的所有位都向左移動若干位,在c中用 運算子.例如 int i 1 i i 2 把i裡的值左移2位 也就是說,1的2進製是000.0001 這裡1前面0的個數和int的位數有關,32位機器,gcc裡有31個0 左移2位之後變成 000.0100,也就是10進製的4,所以說左移...
c語言負數左移右移 C語言中的左移與右移
先說左移,左移就是把乙個數的所有位都向左移動若干位,在c中用 i i 2 把i裡的值左移2位也就是說,1的2進製是000.0001 這裡1前面0的個數和int的位數有關,32位機器,gcc裡有31個0 左移2位之後變成000.0100,也就是10進製的4,所以說左移1位相當於乘以2,那麼左移n位就是...
c語言負數左移右移 C語言中關於迴圈左移和迴圈右移
昨天在解答同學的問題中,又接觸了好久沒碰的c中的位操作。在重接觸的過程中,又理解了一遍計算機儲存資料的細節,於是分享給大家看一下。讓我們先看一下題目 編寫乙個程式,輸入兩個整數i j,如果j的值大於0,則將i迴圈左移j位 如果j的值小於0,則將i迴圈右移j位,最後輸出i的值。輸入輸出格式要求 輸入格...