基本的な演算子については第4章で説明しましたが、この章では、もう少し複雑な演算子について説明します。まず、ビット単位の論理演算子とシフト演算子を取り上げます。
1. ビット単位の論理演算子
ビット単位でデータ操作をするものです。対象は整数に限られます。
演算子 | 説明 |
---|---|
& | ビットごとの AND |
| | ビットごとの OR |
^ | ビットごとの XOR |
~ | ビットごとの反転(1 の補数) |
<< | 左シフト |
>> | 右シフト |
(1) &(AND)
0 & 0 → 0
0 & 1 → 0
1 & 0 → 0
1 & 1 → 1
両方のビットが 1 のときのみ結果が 1 になるビット演算です。
10101010 and 11110000 ーーーーーーー 10100000
必要なビット以外をOFF(0)にする処理(マスクといいます)に使用されます。
例えば、10101010 という1バイトのビット列の下位4ビットを OFF する場合、そのままにしたいビットを 1 、OFFしたいビットを 0 にした、11110000 で and することにより実現できます。
unsigned char a = 0xaa; // 10101010
printf("%#x\n",a & 0xf0); // and 11110000
【実行結果例】
0xa0
(2) |(OR)
0 | 0 → 0
0 | 1 → 1
1 | 0 → 1
1 | 1 → 1
いずれかのビットが 1 なら結果が 1 になるビット演算です。
10101010 or 11110000 ーーーーーーー 11111010
必要なビットをON(1)にする場合に or は使われます。
例えば、10101010 という1バイトのビット列の上位4ビットを ON する場合、ONにしたいビットを 1 、そのままにしたいビットを 0 にした、11110000 で or することにより実現できます。
unsigned char a = 0xaa; // 10101010
printf("%#x\n",a | 0xf0); // or 11110000
【実行結果例】
0xfa
(3) ^(XOR)
0 ^ 0 → 0
0 ^ 1 → 1
1 ^ 0 → 1
1 ^ 1 → 0
両方のビットが異なるときに結果を 1 にするビット演算です。
10101010 xor 00001111 ーーーーーーー 10100101
特定なビットを反転する場合に xor は使われます。
例えば、10101010 という1バイトのビット列の下位4ビットを反転する場合、反転したいビットを 1 、そのままにしたいビットを 0 にした、00001111 で xor することにより実現できます。
unsigned char a = 0xaa; // 10101010
printf("%#x\n",a ^ 0x0f); // xor 00001111
【実行結果例】
0xa5
(4) ~(補数)
0 → 1
1 → 0
両方のビットが異なるときに結果を 1 にするビット演算です。
全ビットの無条件反転を行います。
unsigned char a = 0xaa; // 10101010
printf("%#x\n",~a);
【実行結果例】
0xffffff55
〇演習問題
任意の 2つの unsigned int型で表すことのできる整数値を入力し、 論理積(AND)、論理和(OR)、排他的論理和(XOR)を求めて表示せよ。
ただし、表示はわかりやすいように16進数で行うこと。
【実行結果例】
0~4294967295の整数を2つ入力
65530
65535
65530(0xfffa) AND 65535(0xffff) = 0xfffa
65530(0xfffa) OR 65535(0xffff) = 0xffff
65530(0xfffa) XOR 65535(0xffff) = 0x5
※ 水色字はキーボードからの入力
解答例
#include <stdio.h>
#include <limits.h>
int main(void)
{
unsigned int x, y, z;
printf("0~%uの整数を2つ入力\n", UINT_MAX);
scanf("%u%u", &x, &y );
z = x & y;
printf("%u(%#x) AND %u(%#x) = %#x\n", x, x, y, y, z);
z = x | y;
printf("%u(%#x) OR %u(%#x) = %#x\n", x, x, y, y, z);
z = x ^ y;
printf("%u(%#x) XOR %u(%#x) = %#x\n", x, x, y, y, z);
return 0;
}
2. シフト演算子
(1) <<(左シフト)
- x << n と書き、x を n ビット左へシフトします。
- 右側の空いたビットには 0 が入り、左側のビットは捨てられます。
- 左シフトは x が正の場合あふれがなければ、x << 1 で「x * 2」を計算することと同じになります。
// 正の整数のとき
int x = 100;
x = x << 2;
printf("%#x\n", x);
【実行結果例】
0x190

(2) >>(右シフト)
- x >> n と書き、x を n ビット右へシフトします。
- 左側の空いたビットには、x が符号無しなら 0 が入ります。x が符号付きなら、算術シフトを行う処理系では符号桁が入り、論理シフトを行う処理系では 0 が埋められます。 右側のビットは算術シフト、論理シフトにかかわらず捨てられます。
- 負の数のシフトは処理系依存です。扱いには注意が必要です。
- 右シフトは x が正の場合あふれがなければ 、x >> 1 で「x / 2」を計算することと同じになります。
// 正の整数のとき
int x = 100;
x = x >> 2;
printf("%#x\n", x);
【実行結果例】
0x19

// 負の整数のとき
int x = -100;
x = x >> 2;
printf("%#x\n", x);
【実行結果例】
0xffffffe7

〇 演習問題
次の手順で、整数値以外の値が入力されるまで、任意の unsigned int型で表すことのできる整数値を入力し、 そのビットパターンを表示するプログラムを作成しなさい。
- main関数で次の処理を行う。
- 任意のunsigned int型で表すことのできる10進整数を入力する。入力した整数を引数にして、ビットパターン表示関数 bit_disp( ) を呼ぶ。
- 整数値以外の値が入力されたら、プログラムを終了する。
- bit_disp関数の仕様は以下である。
- 関数宣言:void bit_disp( unsigned int dt );
- 引数: dt … 任意の 符号無し10進整数
- 返却値:なし
- 処理:unsigned int ビットサイズ分ループする。最上位ビットから順にビットパターン(0 or 1)を表示する。
【実行結果例】
0~4294967295の整数を入力(終了条件:整数値以外)
0
0 —> 00000000000000000000000000000000
32767
0x7fff —> 00000000000000000111111111111111
4294967295
0xffffffff —> 11111111111111111111111111111111
a
※ 水色字はキーボードからの入力
解答例
#include <stdio.h>
#include <limits.h>
void bit_disp(unsigned int dt);
int main(void)
{
unsigned int a;
printf("0~%uの整数を入力(終了条件:整数値以外)\n", UINT_MAX);
while(scanf("%u", &a ) == 1){
bit_disp(a);
}
return 0;
}
/*** ビット表示関数 ***/
void bit_disp(unsigned int dt)
{
int i, len;
// unsigned int のビット数をlenにセット
len = sizeof(dt) * CHAR_BIT;
printf("%#x ---> ", dt);
for (i = len - 1; i >= 0; i--){
// ビットの表示
printf("%u", (dt >> i) & 0x0001);
}
printf("\n");
}
コメント