【汎整数拡張】第5回 算術シフトと論理シフト

ついに来ました、ビットシフト。みんな大好きビットシフト。

signed型の負数に対する右ビットシフトの結果は処理系依存なので、以下の話はgcc限定ととらえて下さい。

まずは、unsigned char型のビットシフトから。
unsigned型のビットシフトは解説するところが無いほど簡単です。

-----------------------------------
 unsigned char 0x7Fの左4ビットシフト
-----------------------------------
> unsigned char : 127(0x7F)
0111 1111
> unsigned char -> int(汎整数拡張)
0000 0000 0000 0000 0000 0000 0111 1111
> uc<<4
0000 0000 0000 0000 0000 0111 1111 0000

-----------------------------------
 unsigned char 0x80の左4ビットシフト
-----------------------------------
> unsigned char : 128(0x80)
1000 0000
> unsigned char -> int(汎整数拡張)
0000 0000 0000 0000 0000 0000 1000 0000
> uc<<4
0000 0000 0000 0000 0000 1000 0000 0000

-----------------------------------
 unsigned char 0x7Fの右4ビットシフト
-----------------------------------
> unsigned char : 127(0x7F)
0111 1111
> unsigned char -> int(汎整数拡張)
0000 0000 0000 0000 0000 0000 0111 1111
> uc>>4
0000 0000 0000 0000 0000 0000 0000 0111

-----------------------------------
 unsigned char 0x80の右4ビットシフト
-----------------------------------
> unsigned char : 128(0x80)
1000 0000
> unsigned char -> int(汎整数拡張)
0000 0000 0000 0000 0000 0000 1000 0000
> uc>>4
0000 0000 0000 0000 0000 0000 0000 1000

というように、空いたビットを0で埋める。それだけです。

つぎに、char型のビットシフトについて。

-----------------------------------
 char 0x7Fの左4ビットシフト
-----------------------------------
> char : 127(0x7F)
0111 1111
> char -> int(汎整数拡張)
0000 0000 0000 0000 0000 0000 0111 1111
> c<<4
0000 0000 0000 0000 0000 0111 1111 0000

-----------------------------------
 char 0x80の左4ビットシフト
-----------------------------------
> char : 128(0x80)
1000 0000
> char -> int(汎整数拡張)
1111 1111 1111 1111 1111 1111 1000 0000
> c<<4
1111 1111 1111 1111 1111 1000 0000 0000

-----------------------------------
 char 0x7Fの右4ビットシフト
-----------------------------------
> char : 127(0x7F)
0111 1111
> char -> int(汎整数拡張)
0000 0000 0000 0000 0000 0000 0111 1111
> c>>4
0000 0000 0000 0000 0000 0000 0000 0111

-----------------------------------
 char 0x80の右4ビットシフト
-----------------------------------
> char : 128(0x80)
1000 0000
> char -> int(汎整数拡張)
1111 1111 1111 1111 1111 1111 1000 0000
> c>>4
1111 1111 1111 1111 1111 1111 1111 1000

signed型の左ビットシフトの場合、空いたビットは0で埋められます(unsigned char型の場合と同じ)。右ビットシフトの場合、空いたビットは符号ビットと同じビットで埋められます。

ビットシフトによって空いたビットを何の値で埋めるか、というのをまとめると、

  左ビットシフト 右ビットシフト
char型 0 符号ビット
unsigned char型 0 0

となります。

ビットシフトにより発生した空きビットが0で埋められる場合は「論理シフト」、空きビットが符号ビットと同じビットで埋められる場合は「算術シフト」と言います。前者は符号の影響を受けず、単純にビットイメージの操作となるため「論理」、後者は符号の影響を受けるため「算術」、と覚えると覚えやすいです。

(1)signed型の右ビットシフトは算術シフトが発生する(gcc4.4.7)ため符号に注意することと、(2)式中での評価時に汎整数拡張が行われること。この2点に注意すれば、もう大丈夫ですね。あと繰り返しになりますが、signed型の負数について、右ビットシフトにより論理シフトが発生するか算術シフトが発生するかは処理系依存なので、実際の挙動については、必ずコンパイラの仕様を確認するようにして下さい。