04 ビット演算

ビット演算は、整数値を ビット(0と1)単位で操作する演算である。効率的な計算やデータの操作が可能になる。2級では、各演算子の動作・シフトと2倍/半分の関係・符号付き右シフトの挙動・ビットマスクが問われる。

✅ この章のゴール:① 4つのビット演算子 &(AND) |(OR) ^(XOR) ~(NOT) の動作が分かる ② 左シフト <<=×2/右シフト >>=÷2 を説明できる ③ 符号付き右シフトは符号ビットを維持・符号なしは0挿入 を区別できる ④ ビットマスクで特定ビットを取得(&)・設定(|)できる。

04-1 ビット演算子の紹介

整数を2進数とみなし、ビットごとに演算する。基本は次の4つ。

演算子名称動作概要例(2進数)
&ビットごとの論理積(AND)両方のビットが1のときだけ1、それ以外は01101 & 1011 = 1001
|ビットごとの論理和(OR)少なくとも1つのビットが1なら11101 | 1011 = 1111
^排他的論理和(XOR)2つのビットが異なるとき1(同じなら0)1101 ^ 1011 = 0110
~ビットの反転(NOT)各ビットを反転(0→1、1→0)~1101 = 0010
⚠ ビット演算子 & | は、論理演算子 && ||(条件式の AND/OR)とは別物。ビット演算子は1ビットずつ、論理演算子は「真偽(0かそれ以外か)」全体を見る。

ビットごとに見るとどうなるか

1101 & 1011 を桁ごとにそろえて計算すると、両方が1の桁だけ1になる。

    1 1 0 1
  &) 1 0 1 1
  ---------
    1 0 0 1    ← 両方1の桁だけ1

04-2 ビットシフト(<< と >>)

シフト演算はビットの並びを左右にずらす演算である。

演算子動作意味
x << nビットを左に n 個ずらし、右側に0を入れる×2n(1回で2倍)
x >> nビットを右に n 個ずらす÷2n(1回で半分)

左シフト(×2)の例

x = 5(2進数 0000 0101)をシフトする。

5 << 1 :  0000 0101  →  0000 1010   (10進数 10 = 5×2)
5 << 2 :  0000 0101  →  0001 0100   (10進数 20 = 5×4)

右シフト(÷2)の例

20(2進数 0001 0100)をシフトする。

20 >> 1 :  0001 0100  →  0000 1010   (10進数 10 = 20÷2)
20 >> 2 :  0001 0100  →  0000 0101   (10進数  5 = 20÷4)
左シフト1回=×2、右シフト1回=÷2x << 3 なら ×8(2の3乗)。乗算・除算をシフトで高速に置き換えられる、というのがビットシフトの旨み。

ビット演算を使わない場合との比較

同じ「2倍・4倍」は、ふつうの算術でもシフトでも書ける。

int x;
int result1;
int result2;
int result3;

x = 5;
result1 = x * 2;    /* 通常の算術:2倍  → 10 */
result2 = x * 4;    /* 通常の算術:4倍  → 20 */

result1 = x << 1;   /* シフト:2倍 → 10(0000 0101 → 0000 1010) */
result2 = x << 2;   /* シフト:4倍 → 20 */
result3 = x >> 1;   /* シフト:1/2 → 2(端数は切り捨て) */
⚠ 整数のシフトに小数は出ない。5 >> 10000 0101 → 0000 00102(2.5 ではなく切り捨て)。

04-3 符号付き右シフトの注意点

右シフトは「左側に何を入れるか」が型で変わる。ここが2級頻出

負の数は2の補数で表される。-8 は8ビットで 1111 1000。これを右シフトすると:

-8 >> 1 :  1111 1000  →  1111 1100   (10進数 -4)
                            ↑
                左側に符号ビット 1 が入る(符号が保たれる)
符号付きの右シフトは符号ビット(1)が維持されるので、-8 >> 1-4(負のまま、値は半分)。もし左側に0を入れてしまうと正の大きな数になってしまう。符号なしなら常に0挿入。

オーバーフロー(シフトしすぎ)の注意

⚠ 型のビット幅以上シフトしても意味がない(未定義動作)。たとえば32ビット int で 5 << 32 は無効。「ビット数を超えるシフトはしない」と覚える。

04-4 ビットマスク(特定ビットの取得・設定)

ビット演算は、整数の「特定の位置のビットだけ」を取り出したり立てたりするのに便利。これに使う値を マスク と呼ぶ。

① 特定ビットを取得する → &(AND)

取り出したい桁だけ1にしたマスクと & を取ると、その桁だけが残る。

unsigned short x;
unsigned short mask;
unsigned short result;

x      = 0x5A;   /* 0101 1010 */
mask   = 0x0F;   /* 0000 1111  ← 下位4ビットだけ1 */
result = x & mask;   /* 下位4ビットを取得 */
    0101 1010   (x    = 0x5A)
  &) 0000 1111   (mask = 0x0F)
  -----------
    0000 1010   (result = 0x0A = 10進数 10)

上位4ビットは 0 & … で消え、下位4ビットだけが残る。

② 特定ビットを設定(1にする)→ |(OR)

立てたい桁だけ1にしたマスクと | を取ると、その桁が必ず1になる(他の桁は変わらない)。

unsigned short x;
unsigned short mask;
unsigned short result;

x      = 0x5A;   /* 0101 1010 */
mask   = 0x01;   /* 0000 0001  ← 最下位ビットだけ1 */
result = x | mask;   /* 最下位ビットを1に設定 */
    0101 1010   (x    = 0x5A)
  |) 0000 0001   (mask = 0x01)
  -----------
    0101 1011   (result = 0x5B = 10進数 91)
取得(取り出す)は &、設定(1を立てる)は |。ついでに「反転(トグル)は ^」もセットで覚えると強い。

04-5 まとめ


04-6 📝 過去問で確認

過去問(ビット演算)— まず自分で解いてみよう
ビット演算の過去問 問題
問題
解説を表示
ビット演算の過去問 解説
解説

04-7 理解度チェック

Q1. 次のコードの result の値はどれか。

int x = 6;
int result = x << 2;
解説を表示

正解:イ(24)

左シフト1回が×2なので、<< 2 は ×4。6×4 = 24。2進数では 0000 0110 → 0001 1000(10進数 24)。

Q2. 次のコードの result の値はどれか。

unsigned short x    = 0x3C;   /* 0011 1100 */
unsigned short mask = 0x0F;   /* 0000 1111 */
unsigned short result = x & mask;
解説を表示

正解:ア(0x0C)

& は両方1の桁だけ残す。マスク 0x0F0000 1111 は下位4ビットだけ1なので、0011 1100 & 0000 1111 = 0000 11000x0C。下位4ビットの取得。

Q3. 次のコードの result の値はどれか。

signed int x = -8;   /* 1111 1000(2の補数表現) */
signed int result = x >> 1;
解説を表示

正解:ア(-4)

符号付き整数の右シフトは 符号ビット(1)が維持されるため、1111 1000 → 1111 1100 となり 10進数 -4。値は半分(÷2)になり、符号は負のまま保たれる。符号なしなら左側に0が入る。

Q4. 2進数の計算 1101 & 1011 の結果はどれか。

解説を表示

正解:ウ(1001)

AND は両方のビットが1の桁だけ1。桁ごとに見ると 1&1=11&0=00&1=01&1=11001。なお同じ組み合わせで OR なら 1111、XOR なら 0110

Q5. 整数のあるビットを「1に設定する(立てる)」のに使う演算子はどれか。

解説を表示

正解:イ(OR)

立てたい桁だけ1にしたマスクと | を取ると、その桁が必ず1になる(他は不変)。逆に特定ビットを取得するなら &(AND)を使う。