C言語のビットをシフト演算子で操作する【<<, >>, 左シフト、右シフト】

487, 2022-06-06

目次

C言語のビットをシフト演算子で操作する

今回はC言語のビット演算のうち、シフト演算子について解説します。

変数などの持つ値のビット列を操作することをビット演算と言います。
そのビット演算の中でビットを左にシフトしたり右にシフトしたりする演算をシフト演算と言います。

この記事を読めばビット列へのシフト演算がわかります。
ビット演算の理解を深めたい方におすすめです。

関連記事


ビット列を表示する関数を作る

今回はシフト演算の理解のために変数のビット列を出力する関数を作ります。
この関数もシフト演算を使ってます。

#include <stdio.h>

void show_bits(int var) {
    int nbytes = sizeof(var);
    int nbits = nbytes * 8;

    printf("%4d -> ", var);

    for (int i = nbits - 1; i >= 0; i -= 1) {
        int n = var >> i;
        if (n & 1) {
            putchar('1');
        } else {
            putchar('0');
        }
        if (i > 0 && i % 4 == 0) {
            putchar(' ');
        }
    }
    puts("");
}

int main(void) {
    show_bits(0);
    show_bits(1);
    show_bits(8);
    show_bits(32);
    show_bits(64);
    show_bits(255);
    show_bits(256);
    return 0;
}

↑のコードを実行すると↓の結果になります。

   0 -> 0000 0000 0000 0000 0000 0000 0000 0000
   1 -> 0000 0000 0000 0000 0000 0000 0000 0001
   8 -> 0000 0000 0000 0000 0000 0000 0000 1000
  32 -> 0000 0000 0000 0000 0000 0000 0010 0000
  64 -> 0000 0000 0000 0000 0000 0000 0100 0000
 255 -> 0000 0000 0000 0000 0000 0000 1111 1111
 256 -> 0000 0000 0000 0000 0000 0001 0000 0000

この関数の原理については今回は理解しなくてもOKです。
シフト演算子の理解とはまた違うベクトルの話になるからです。

しかし興味がある人のために簡単に解説します。

show_bits()関数では引数varのビット数を最初に計算します。
sizeof(var)で変数varのバイト数、それに8をかけてビット数にします。

ループを回しながらvarをカウント変数で右シフトします。
こうするとビット列がカウント変数分だけ右に移動します。
その移動したビット列(変数n)を1でANDを取ります。
仮にnの最下部のビットが立っていたらこの式は真になります。

最下部のビットが立っていたら1と出力し、立っていなかったら0と出力します。
ビット列の桁をずらしながらすべてのビットでこのようにしていきます。
そうすると最終的にvarの各ビット10で表現されます。

4ビットごとに空白スペースを入れて出力を見やすくしています。
最後に改行を入れて完了です。

右シフトについて学ぶ

シフト演算の内、変数のビット列を右にシフトする演算を「右シフト演算」と言います。
この演算を行うとビット列を右にずらせます。

式の書き方は↓です。

値 >> シフトする数

左の値には即値や変数を起きます。
>>が右シフト演算子ですが、右にさきっちょが向いてますね。
右シフト演算子はビット列を右にずらしますが、>>の右側にはいくつずらすかその数を書きます。

先ほどshow_bits()関数を使って右シフトの結果を見てみます。

    int n = 8;
    show_bits(n);

    n = n >> 1;
    show_bits(n);

変数n8を代入して、それを1だけ右シフトしています。
n >> 1が右シフト演算です。
そうすると結果は↓のようになります。

   8 -> 0000 0000 0000 0000 0000 0000 0000 1000
   4 -> 0000 0000 0000 0000 0000 0000 0000 0100

整数8は右から4つ目のビットが立っています。
これはビット列では1000ですが、これは2進数になります。
10進数に直すと10008になります。

それで1ビットだけ右シフトした変数は整数では4になります。
値が半分になっていますね。
そしてビット列を見ると0100になっていて、1のビットが右に1つずれているのがわかります。
これは右シフト演算でビット列を右にシフトしたからです。

では次は整数82ビット右にシフトしてみます。

    n = 8;
    show_bits(n);

    n = n >> 2;
    show_bits(n);
   8 -> 0000 0000 0000 0000 0000 0000 0000 1000
   2 -> 0000 0000 0000 0000 0000 0000 0000 0010

そうすると今度は82になりました。
ビット列を見ると10000010になっています。
これは右シフト演算で2だけ右にシフトしたからです。

1だけ右にシフトすると84になり1/2になりました。
そして2だけ右にシフトすると82になり1/4になりました。
では3だけ右シフトするとどうなるでしょうか?

    n = 8;
    show_bits(n);

    n = n >> 3;
    show_bits(n);
   8 -> 0000 0000 0000 0000 0000 0000 0000 1000
   1 -> 0000 0000 0000 0000 0000 0000 0000 0001

そうすると今度は81になりました。
1/8ですね。
ビット列は1000から0001です。

こういう感じで右シフト演算は値を1/2, 1/2...にしていきます。
ビット列は右に1つずつずれます。
ビット列が右に1つずれると値は1/2になる、と覚えておくとわかりやすいと思います。

左シフトについて学ぶ

右シフトは値を1/2, 1/2...にしていきました。
左シフトはその逆で値を2倍、2倍にしていきます。

左シフト演算子の式の書き方は↓です。

値 << シフトする数

show_bits()でビット列を見てみましょう。

    n = 8;
    show_bits(n);

    n = n << 1;
    show_bits(n);
   8 -> 0000 0000 0000 0000 0000 0000 0000 1000
  16 -> 0000 0000 0000 0000 0000 0000 0001 0000

そうすると↑のように8の値が16になります。
ビット列は0000 10000001 0000になりました。
こういう感じで左シフトはビット列を左にシフトします。

ビット列が1だけ左にシフトするとその値は倍になります。
では次は2だけ左シフトしてみます。

    n = 8;
    show_bits(n);

    n = n << 2;
    show_bits(n);

そうすると結果は↓になります。

   8 -> 0000 0000 0000 0000 0000 0000 0000 1000
  32 -> 0000 0000 0000 0000 0000 0000 0010 0000

整数の832になりました。
4倍になってますね。
ビット列は左に2だけシフトしています。

このように左シフトは値を2倍、2倍...にしていきます。
そしてビット列は左にずれていきます。

ビット演算はビット列で視覚的に確認すると理解しやすいです。
よくわからなくなったらビット列を確認しましょう。

代入シフト演算子

右シフト演算子と左シフト演算子には親戚がいます。
それは↓の演算子です。

>>=
<<=

これらの演算子は変数に対して直接シフト演算を行います。
つまり変数の値を操作します。

たとえば↓のようにすると

    n = 8;

    n >>= 1;
    show_bits(n);

    n <<= 2;
    show_bits(n);


結果は↓のようになります。

   4 -> 0000 0000 0000 0000 0000 0000 0000 0100
  16 -> 0000 0000 0000 0000 0000 0000 0001 0000

n >>= 1;n = n >> 1;と同じ結果になります。
n <<= 2;n = n << 2;と同じ結果です。

これは足し算の+=演算子などと同じ感じの演算子です。

おわりに

今回はC言語のビット列をシフトする演算子を解説しました。
ビット演算は上級者向けの演算ですが慣れておくと意外に便利です。
理解が難しくなったらビット列を確認するクセをつけておくと吉です。

(^ _ ^)

ようこそ、ビットを操作するものよ

(・ v ・)

うーん、ハカー



この記事のアンケートを送信する