C言語のビット演算オペレータ

こんにちは、未来のコーディングの魔法使いたち!今日、私たちはC言語のビット演算オペレータのワクワクする世界に旅立つことにします。プログラミングに初めての方でも心配しないでください。私があなたの友好的なガイドとして、すべてをステップバイステップで説明します。だから、学習用の帽子をかぶって、一緒に飛び込みましょう!

C - Bitwise Operators

ビット演算オペレータとは?

始める前に、ビット演算オペレータって何か理解しましょう。一斉にライトスイッチをいくつか想像してください。ビット演算オペレータは、これらのスイッチを興味深い方法で制御するための特別なツールです - それらをオンやオフにするだけでなく、状態を交換することさえ可能です。コンピュータの世界では、これらの「スイッチ」は実際にはデータを構成するビット(0と1)です。

では、ひとつひとつビット演算オペレータを探ってみましょう。

C言語のビット単位AND演算子(&)

ビット単位AND演算子は、両方の入力が合意するとだけ「はい」と言う気狭い友達のようです。2つの数の各ビットを比較し、両方のビットが1の場合にのみ1を返します。それ以外の場合は0を返します。

例を見てみましょう:

#include <stdio.h>

int main() {
unsigned int a = 60;  // 60 = 0011 1100 でバイナリ表記
unsigned int b = 13;  // 13 = 0000 1101 でバイナリ表記

printf("a & b = %d\n", a & b);

return 0;
}

出力:

a & b = 12

ここで何が起こっているのでしょうか?それを分解してみましょう:

0011 1100  (60のバイナリ)
& 0000 1101  (13のバイナリ)
----------
0000 1100  (12の10進数)

どうやら両方の数が1の場合にのみ1を保持しているようですね?それがビット単位ANDの魔法です!

ビット単位OR演算子(|)

ビット単位OR演算子は、少なくとも一方の入力が合意すると「はい」と言う寛大な友達のようです。対応するビットの少なくとも1つが1の場合に1を返します。

以下が例です:

#include <stdio.h>

int main() {
unsigned int a = 60;  // 60 = 0011 1100 でバイナリ表記
unsigned int b = 13;  // 13 = 0000 1101 でバイナリ表記

printf("a | b = %d\n", a | b);

return 0;
}

出力:

a | b = 61

それを分解してみましょう:

0011 1100  (60のバイナリ)
| 0000 1101  (13のバイナリ)
----------
0011 1101  (61の10進数)

どうやらどちらかの数が1の場合に1を保持しているようですね?それがビット単位ORです!

ビット単位XOR演算子(^)

XOR演算子は、異なることを好む妙な友達のようです。ビットが異なる場合に1を返し、同じ場合に0を返します。

それを動かしてみましょう:

#include <stdio.h>

int main() {
unsigned int a = 60;  // 60 = 0011 1100 でバイナリ表記
unsigned int b = 13;  // 13 = 0000 1101 でバイナリ表記

printf("a ^ b = %d\n", a ^ b);

return 0;
}

出力:

a ^ b = 49

ここで何が起こっているのか見てみましょう:

0011 1100  (60のバイナリ)
^ 0000 1101  (13のバイナリ)
----------
0011 0001  (49の10進数)

XORは暗号技術によく使われます。なぜなら、逆転しやすいからです。数を同じ値で2回XORすると、元の数に戻ります。クールでしょう?

左シフト演算子(<<)

左シフト演算子は、ビットを左に動かすコンベアベルトのようです。各ビットを指定された数の位置だけ左にシフトします。

以下がその仕組みです:

#include <stdio.h>

int main() {
unsigned int a = 60;  // 60 = 0011 1100 でバイナリ表記

printf("a << 2 = %d\n", a << 2);

return 0;
}

出力:

a << 2 = 240

それを分解してみましょう:

0011 1100  (60のバイナリ)
<<2 (左に2シフト)
----------
1111 0000  (240の10進数)

ビットが左に動いて、右から新しい0が埋められたのが見えますか?また、1シフト左は2倍に相当します。したがって、2シフト左は4倍に相当します!

右シフト演算子(>>)

右シフト演算子は、左シフトの逆のような双子のようです。ビットを右に動かします。

例を見てみましょう:

#include <stdio.h>

int main() {
unsigned int a = 60;  // 60 = 0011 1100 でバイナリ表記

printf("a >> 2 = %d\n", a >> 2);

return 0;
}

出力:

a >> 2 = 15

ここで何が起こっているのか見てみましょう:

0011 1100  (60のバイナリ)
>>2 (右に2シフト)
----------
0000 1111  (15の10進数)

ビットが右に動いて、左から新しい0が埋められました。右に1シフトは2で割る(余りを無視して)に相当します。

1の補数演算子(~)

1の補数演算子は、ビットのミラーのようです。すべてのビットを0から1へ、そして1から0へ反転します。

以下がその仕組みです:

#include <stdio.h>

int main() {
unsigned int a = 60;  // 60 = 0011 1100 でバイナリ表記

printf("~a = %u\n", ~a);

return 0;
}

出力:

~a = 4294967235

ここで何が起こったのでしょうか?それを分解してみましょう:

0000 0000 0000 0000 0000 0000 0011 1100  (60の32ビットバイナリ)
~(1の補数)
----------------------------------------
1111 1111 1111 1111 1111 1111 1100 0011  (4294967235の10進数)

すべての0が1に、すべての1が0に反転しました。結果が大きく見えるのは、無符号整数を使用していて、すべての1を正の数として解釈しているからです。

結論

それで、お終いです、みんな!私たちはC言語のビット演算オペレータの地を旅しました。これらの強力なツールは最初は少し厄介に見えるかもしれませんが、練習すれば非常に有用になります。ハードウェアとの連携、コードの最適化、またはちょっとしたパーティのトリック(もしあなたのパーティにバイナリ計算があるなら)などのタスクに役立ちます。

覚えておきましょう、これらのオペレータをマスターする鍵は練習です。これらのオペレータを使った独自のプログラムを書いてみてください。異なる数を使ってどんな結果が得られるか試してみてください。知らずにいつの間にか、彼らの中でも最も優れたビット操作を行う者になっていることでしょう!

幸せなコーディングを、そしてビットが常にあなたに味方であることを願っています!

演算子 シンボル 説明
AND & 両方のビットが1の場合にのみ1を返し、それ以外は0を返す
OR | 少なくとも一方のビットが1の場合に1を返し、それ以外は0を返す
XOR ^ ビットが異なる場合に1を返し、同じ場合に0を返す
左シフト << ビットを指定された数の位置だけ左にシフトする
右シフト >> ビットを指定された数の位置だけ右にシフトする
1の補数 ~ すべてのビットを反転(0が1に、1が0に)

Credits: Image by storyset