ビット演算子
ビット単位の演算を行うものをビット演算(bitwise operator)といいます。ビット論理演算子(bitwise logical operator)ともいいます。
- &:ビット積演算子。ビット単位で比較してともに1なら1
- |:ビット和演算子。どちらかが1なら1
- ^:ビット差演算子。互いに異なれば1
まずはサンプルを見てみましょう。
ソースコード
源文件
1|
2|
3|#include <stdio.h>
4|
5|int main(void)
6|{
7| unsigned short a, b;
8|
9| a = 1;
10| b = 3;
11|
12| printf("a & b = %d\n", a & b);
13| printf("a | b = %d\n", a | b);
14| printf("a ^ b = %d\n", a ^ b);
15|
16| return 0;
17|}
|
実行結果
a & b = 1
a | b = 3
a ^ b = 2
|
ここでは、short 型を2バイトとします。このとき、
1を2進法で表すと、0000 0000 0000 0001
3を2進法で表すと、0000 0000 0000 0011
ビット演算の利用方法
「ビット演算なんてどんなとき使うの?」
ソースコード
源文件
1|
2|
3|#include <stdio.h>
4|
5|#define CAT 1
6|#define DOG 2
7|#define RAT 4
8|#define RABBIT 8
9|
10|int main(void)
11|{
12| int a = CAT | DOG;
13| int b = RAT;
14| int c = CAT | DOG | RAT | RABBIT;
15| int d = DOG | RAT;
16|
17| printf("Aさんのペット(猫=%d, 犬=%d, ネズミ=%d, ウサギ=%d)\n",
18| (a & CAT) != 0, (a & DOG) != 0, (a & RAT) != 0, (a & RABBIT) != 0) ;
19| printf("Bさんのペット(猫=%d, 犬=%d, ネズミ=%d, ウサギ=%d)\n",
20| (b & CAT) != 0, (b & DOG) != 0, (b & RAT) != 0, (b & RABBIT) != 0) ;
21| printf("Cさんのペット(猫=%d, 犬=%d, ネズミ=%d, ウサギ=%d)\n",
22| (c & CAT) != 0, (c & DOG) != 0, (c & RAT) != 0, (c & RABBIT) != 0) ;
23| printf("Dさんのペット(猫=%d, 犬=%d, ネズミ=%d, ウサギ=%d)\n",
24| (d & CAT) != 0, (d & DOG) != 0, (d & RAT) != 0, (d & RABBIT) != 0) ;
25|
26| return 0;
27|}
|
実行結果
Aさんのペット(猫=1, 犬=1, ネズミ=0, ウサギ=0)
Bさんのペット(猫=0, 犬=0, ネズミ=1, ウサギ=0)
Cさんのペット(猫=1, 犬=1, ネズミ=1, ウサギ=1)
Dさんのペット(猫=0, 犬=1, ネズミ=1, ウサギ=0)
|
>飼っているペットを「|」演算子でつないています。ここで、Aさんがネズミを飼っているかどうかを調べるときは(a & RAT)の値を調べます。飼っていなければ0、飼っていれば0以外の値をなります。そのたの動物についても同じように調べることができます。
どうしてこんなことができるのでしょうか。それには、各ペットに割当られている数字にヒントがあります。例えばプログラム冒頭部分の「#define CAT 1」で、CATに1割当てています。これらの数字をよく見ると、CAT,DOG,RAT,RABBITの値が2倍、2倍となっていることに気づきます。これを2進法で表してみましょう。
- CAT
- 0000 0001
- DOG
- 0000 0010
- RAT
- 0000 0100
- RABBIT
- 0000 1000
各ペットのビットで1となっているのは一つのみです。さて、それぞれのペットのビットが1になっているかどうかは「ペットの値 & 調べたい値」でわかります。つまり、調べたい値のそのペットのビットが1になっていれば、0以外の値になります。例えば(CAT | DOG)の値は(0000 0011)です。これに CAT(0000 0001)が含まれているかどうかをしらべるには
(0000 0001) & (0000 0011)
の値を調べます。この演算結果は0以外の値となります。
補数の演算子
この他に「~」という演算子(補数演算子)があります。このは、各ビットの反転させます。
ソースコード
源文件
1|
2|
3|#include <stdio.h>
4|
5|int main(void)
6|{
7| int a = 10;
8|
9| printf(" a = %08X\n~a = %08X\n", a, ~a);
10|
11| return 0;
12|}
|
実行結果
a = 0000000A
~a = FFFFFFF5
|
10は32ビットで表すと
(0000 0000 0000 0000 0000 0000 0000 1010)
となり、これを16進数に直すと0x0000000A。ビット反転すると
(1111 1111 1111 1111 1111 1111 1111 0101)
となり、これを16進数に直すと0xFFFFFFF5です。
シフト演算子
シフト演算子というものもあります。これは、ビットを右また左にずらす演算子です。かけ算、割り算を高速で処理することができます。
「>>」は、ビットを右にずらします。(1000 0000)のビットを一つ右にずらすと(0100 0000)となります。左にできた隙間は0で埋め、右にはみ出たビットを無視します。これは、値が2分の1になりました。さらにビットを一つ右にシフトすると(0010 0000)となり、またまた値が2分の1になりました。
「>>」を右シフト演算子(right-shift operator)といいます。逆に「<<」を左シフト演算子(left-shift operator)といいます。
ソースコード
源文件
1|
2|
3|#include <stdio.h>
4|
5|int main(void)
6|{
7| short a = 12, b = 100, c = -50;
8|
9| printf("%dを左に1ビットシフト---%d\n", a, a << 1);
10| printf("さらに1ビット左シフト---%d\n", a << 2);
11| printf("さらに1ビット左シフト---%d\n", a << 3);
12| printf("さらに1ビット左シフト---%d\n", a << 4);
13| printf("\n");
14| printf("%dを右に1ビットシフト---%d\n", b, b >> 1);
15| printf("さらに1ビット右シフト---%d\n", b >> 2);
16| printf("さらに1ビット右シフト---%d\n", b >> 3);
17| printf("さらに1ビット右シフト---%d\n", b >> 4);
18| printf("\n");
19| printf("%dを右に1ビットシフト---%d\n", c, c >> 1);
20| printf("%dを左に1ビットシフト---%d\n", c, c << 1);
21|
22| return 0;
23|}
|
実行結果
12を左に1ビットシフト---24
さらに1ビット左シフト---48
さらに1ビット左シフト---96
さらに1ビット左シフト---192
100を右に1ビットシフト---50
さらに1ビット右シフト---25
さらに1ビット右シフト---12
さらに1ビット右シフト---6
-50を右に1ビットシフト----25
-50を左に1ビットシフト----100
|
Chapter3 @ C言語目録 @ HomeWork List @ 昭亮's Homepage