C言語のビット演算子を徹底解説!初心者でもわかる基礎から実践まで
生徒
「先生、C言語で“ビット演算子”っていうのを聞いたんですが、どんなものなんですか?」
先生
「ビット演算子は、数値を細かく扱うための演算子です。コンピュータの世界では、すべてのデータが0と1の組み合わせ、つまり“ビット”で表されています。そのビットを直接操作できるのがビット演算子です。」
生徒
「0と1を直接操作するって難しそうですね…。」
先生
「安心してください。基本を理解すれば簡単です。C言語のビット演算子を使いこなすと、処理を高速化したり、ハードウェア制御などの低レベルな操作もできるようになりますよ。」
1. ビット演算子とは?
ビット演算子とは、整数の二進数表現に対して直接演算を行うための演算子です。C言語では、&, |, ^, ~, <<, >>の6種類があり、データを効率的に扱うための重要な機能です。例えば、LEDの点灯・消灯の制御や、フラグ管理(特定の状態をオン・オフで持つ)などにも使われます。
普段私たちは「10進数(0〜9)」を使いますが、コンピュータは「2進数(0と1)」で動いています。ビット演算子はこの2進数の世界を操作するための道具です。つまり、数の中身を構成するビット単位で考えることができるのです。
2. AND演算子(&)
& は、両方のビットが1のときだけ1になる演算子です。条件を絞り込むときに使います。
#include <stdio.h>
int main(void)
{
unsigned char a = 0b1100; // 12
unsigned char b = 0b1010; // 10
unsigned char c = a & b;
printf("%d\n", c);
return 0;
}
8
上の例では、ビットごとに比較して両方が1の位置だけが1になります。つまり1100 & 1010 = 1000で、結果は8です。これは「両方の条件が成立している部分を取り出す」ようなイメージです。
3. OR演算子(|)
| は、どちらか一方でも1なら1になる演算子です。どちらかが真であれば結果が1になります。
#include <stdio.h>
int main(void)
{
unsigned char a = 0b1100;
unsigned char b = 0b1010;
unsigned char c = a | b;
printf("%d\n", c);
return 0;
}
14
この例では1100 | 1010 = 1110となり、結果は14です。つまり「どちらかの条件でもOK」という考え方です。
4. XOR演算子(^)
^ は、排他的OR(えいてきてきOR)とも呼ばれ、どちらか一方だけが1のときに1になります。両方1の場合は0になる点が特徴です。
#include <stdio.h>
int main(void)
{
unsigned char a = 0b1100;
unsigned char b = 0b1010;
unsigned char c = a ^ b;
printf("%d\n", c);
return 0;
}
6
1100 ^ 1010 = 0110なので、結果は6になります。排他的ORは、データの一部を反転させたり、暗号化処理などにも使われます。たとえば、同じ値で2回XORすると元に戻るという性質があります。
5. NOT演算子(~)
~ は、すべてのビットを反転します。0は1に、1は0になります。
#include <stdio.h>
int main(void)
{
unsigned char a = 0b00001111;
unsigned char b = ~a;
printf("%d\n", b);
return 0;
}
240
この場合、00001111が11110000に反転します。符号付き整数だとマイナスになる場合もあるため、初心者はunsigned型で試すとわかりやすいです。
6. シフト演算子(<< と >>)
シフト演算子はビットを左右に動かします。<<は左シフト、>>は右シフトです。
#include <stdio.h>
int main(void)
{
unsigned char a = 0b00000101;
unsigned char left = a << 1;
unsigned char right = a >> 1;
printf("左シフト: %d\n", left);
printf("右シフト: %d\n", right);
return 0;
}
左シフト: 10
右シフト: 2
左に1ビット動かすと値が2倍になり、右に1ビット動かすと半分になります。これは掛け算・割り算よりも高速なので、数値を高速に操作したい場面で使われます。
7. ビット演算の応用と実用例
ビット演算子は、ハードウェア制御やフラグ管理でよく使われます。例えば、あるデバイスの設定を1バイト(8ビット)で表し、特定のビットをオン・オフして制御できます。
#include <stdio.h>
#define FLAG_A 0x01
#define FLAG_B 0x02
#define FLAG_C 0x04
int main(void)
{
unsigned char flags = 0;
flags |= FLAG_A; // AをON
flags |= FLAG_C; // CをON
if(flags & FLAG_A) printf("Aが有効です。\n");
if(flags & FLAG_B) printf("Bが有効です。\n");
if(flags & FLAG_C) printf("Cが有効です。\n");
return 0;
}
Aが有効です。
Cが有効です。
このようにビット単位で情報を持つことで、メモリを節約しながら多くの状態を同時に管理できます。これはゲーム開発や組み込みシステムなど、リソースが限られた環境で特に重要です。