整数型とビット操作

プログラミングBのページへ戻る

整数とビット

2進数とビット

2進数は,各桁を0か1かで表す表記法であり,その各桁をビットとも呼ぶ. 最も右側のビット(最下位ビット)の番号を第0ビットとして, 左に行くに従い,第1ビット,第2ビット,...と呼ぶ.第 n ビットが表す数値は 2n である.

一番小さいサイズの型である char 型のサイズは 1バイト = 8ビット であるので, 8桁の2進数の各桁の表す数値を表で見てみよう.

ビット番号 76543210
表す数値 1286432168421

たとえば, 77 を表す2進数は 01001101(2) である.

77 = 64 + 8 + 4 + 1 01001101

char 型を構成する 8 ビットのうち, 最上位,すなわちもっとも左側のビットを MSB (most significant bit) といい, 最下位,すなわちもっとも右側のビットを LSM (least significant bit) という.

16進数

4ビットの2進数が表す数値は 0 = 0000(2) から 15 = 1111(2) である.この数値を 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f で表すと, 4ビットを一文字で表すことができ, すなわち1バイト(=8ビット)を2文字で表すことができる. これが16進数表示である.

16進数の第 n 桁(右端を第 0 桁とする)が表す数値は 16n である.

先ほどの 77 の場合は, 77 = 01001101(2) を4桁ごとに区切ると, 0100(2) = 4, 1101(2) = d であるから, 77 = 4d(16) となる.

77 = 64 + 8 + 4 + 1 01001101
77 = 4*16 + 13*1 4d (=13)

現在のコンピュータは4バイトをひとまとまりとして扱うことが多い (例えば int 型は4バイト). 4バイトは 4*8 = 32 ビットであるから,これを2進数で表すと 32 桁にもなる. しかし16進数だと,4ビットを1文字で表すので8文字で表せることになる.

例えば, 7777777 = 00000000011101101010110111110001(2) = 0076adf1(16) である.

2進数 00000000 01110110 10101101 11110001
16進数 0 0 7 6 a d f 1

Cのプログラム中で,整数の定数を16進数で表すことができる. その定数には16進数であることの印のために,頭に 0x を付けることになっている. ( x は16進数 hexadecimal number の x を意味する)

次のプログラムで確かめてみよう.(書式文字列 %x は16進数で整数を表示する指定.)

#include <stdio.h>

int main()
{
  char c;
  int i;

  c = 0x4d;
  i = 0x0076adf1;

  printf("%x = %d\n%x = %d\n", c, c, i, i);
  
  return 0;
}
4d = 77
76adf1 = 7777777

符号無し整数と符号付き整数

C言語では,char 型や int 型などの整数を表す型には, 符号付き(signed)の型と符号無し(unsigned)の型とがある. 符号付きの型は負の数も表すことができるが,符号無しの型は0以上の整数しか表せない. しかし,符号付きの型が表すことができる最大の整数は,符号無しの型が表すことができる 最大の整数の約半分となる.

符号無しの型

char や int などの整数を表す型名に,キーワード unsigned を付けると,それは符号無しの型となる.

    unsigned char c;  /* 符号無し char 型 */
    unsigned int i;   /* 符号無し int 型 */

この場合,表すことのできる最大の整数値は,変数のもつビット数を n とするとき,2n-1 となる.

0 ≦ unsigned char 型の値 ≦ 255 = 28-1

0 ≦ unsigned int 型の値 ≦ 4294967295 = 232-1

符号付きの型

char や int などの整数を表す型名に,キーワード signed を付けると,それは符号付きの型となる.

    signed char c;  /* 符号付き char 型 */
    signed int i;   /* 符号付き int 型 */

この場合,変数のもつビット数を n とするとき,全部で 2n 通りの値を表せるが, それを負の数と正の数とに半々に割り振るので,表すことのできる値の範囲は 最小 -2n-1 から最大 2n-1-1 となる.

-27 = -128 ≦ char型の値 ≦ 127 = 27-1

-231 = -2147483648 ≦ int型の値 ≦ 2147483647 = 231-1

符号無し,符号付きを指定せずに,単に char や int で宣言した場合も, 符号付きの型となる.

    char c;  /* 符号付き char 型 */
    int i;   /* 符号付き int 型 */

じつは,単に char と宣言したときに符号付きになるかどうかは, 処理系依存であるが,符号付きになることが普通である. どちらであるかは, limits.h の中で定義されている CHAR_MAX の値を見ればわかる (次のカラム参照).

ヘッダファイル limit.h には,各種の整数型が表すことのできる数値の最大値と最小値とが, マクロ定数として定義されている.

#include <stdio.h>
#include <limits.h>

int main()
{
  printf("CHAR_MIN  = %4d,      CHAR_MAX  = %4d\n", CHAR_MIN, CHAR_MAX);
  printf("SCHAR_MIN = %4d,      SCHAR_MAX = %4d\n", SCHAR_MIN, SCHAR_MAX);
  printf("UCHAR_MAX = %4d\n", UCHAR_MAX);

  printf("INT_MIN   = %11d,     INT_MAX = %11d\n", INT_MIN, INT_MAX);
  printf("UINT_MAX  = %11u\n", UINT_MAX);
}
CHAR_MIN  = -128,      CHAR_MAX  =  127
SCHAR_MIN = -128,      SCHAR_MAX =  127
UCHAR_MAX =  255
INT_MIN   = -2147483648,     INT_MAX =  2147483647
UINT_MAX  =  4294967295

整数値のビットの状態

コンピュータの内部で整数値がどのようなビット状態で表されるかを見る. 簡単のために unsigned char と signed char とを例にとって説明するが, unsigned int と signed int とについても同様である.

符号無し整数値のビット状態

C言語では,残念ながら整数値を2進数で表示する簡単な方法がない. (16進数なら先ほどのように printf の書式文字列に "%x" で指定すればできた.) そこで,次のような関数を自作して表示させることにする. 関数の内容はまだ理解できなくてもよいので,とりあえずキーボードから打ち込むか, コピー&ペーストして,実行するように.

#include <stdio.h>

/* 符号無し char 型の値と,そのビットの状態を表示する */
void show_unsigned_char(unsigned char x)
{
  int i;

  printf("%4u  %02x  ", x, x); 
 
  for (i = 7; i >= 0; i--) {    
    printf("%d", (x>>i) & 1); 
  }
  printf("\n");
}

int main()
{
  show_unsigned_char(-2);
  show_unsigned_char(-1);
  show_unsigned_char(0);
  show_unsigned_char(1);
  show_unsigned_char(2);
  show_unsigned_char(3);
  show_unsigned_char(127);
  show_unsigned_char(128);
  show_unsigned_char(129);
  show_unsigned_char(254);
  show_unsigned_char(255);
  show_unsigned_char(256);
  show_unsigned_char(257);

  
  return 0;
}

コンパイルすると,次のような警告が出るが,一応コンパイルでき,実行できる.

u_char_bit.c:27: 警告: large integer implicitly truncated to unsigned type
u_char_bit.c:28: 警告: large integer implicitly truncated to unsigned type

実行結果は次のようになる.左から,10進数,16進数,そしてビットの状態である. 符号無し整数値を表すビットの状態は,通常の2進数表記と同一であることに注意しよう.

 254  fe  11111110
 255  ff  11111111
   0  00  00000000
   1  01  00000001
   2  02  00000010
   3  03  00000011
 127  7f  01111111
 128  80  10000000
 129  81  10000001
 254  fe  11111110
 255  ff  11111111
   0  00  00000000
   1  01  00000001

ところで,-2, -1 という負の数を入れたはずなのに,実際には 254, 255 という数値となり, 256, 257 という数値に対しては,0, 1 となっていることにも注意しよう. これは, -2, -1, 256, 257 という定数値が unsigned char が表すことのできる範囲を超えているからである. 先ほどの警告は,このことの警告であった. (定数が範囲を超えているときには,コンパイル時にこのような警告が出ることもあるが, 実行時に変数値が範囲を超えても,警告もエラーも出ない.)

このように, 符号無し char 型の値が,それが表すことのできる範囲を超えてしまった場合, 0, 1, 2, ..., 254, 255 の繰り返しとなる.

符号無し int についても同様に, 0, 1, 2, ... 4294967295 の繰り返しとなる.

符号付きの整数値のビット状態

符号付きの整数値のビットは,2の補数表現という状態になっている.それを見てみよう.

#include <stdio.h>

/* 符号無し char 型の値と,そのビットの状態を表示する */
void show_signed_char(signed char x)
{
  int i;

  printf("%4d  %02x  ", x, (unsigned char)x);
  for (i = 7; i >= 0; i--) {
    printf("%d", (x>>i) & 1);
  }
  printf("\n");
}


int main()
{
  show_signed_char(-130);
  show_signed_char(-129);
  show_signed_char(-128);
  show_signed_char(-127);
  show_signed_char(-3);
  show_signed_char(-2);
  show_signed_char(-1);
  show_signed_char(0);
  show_signed_char(1);
  show_signed_char(2);
  show_signed_char(3);
  show_signed_char(126);
  show_signed_char(127);
  show_signed_char(128);
  show_signed_char(129);

  return 0;
}

これもコンパイルすると,警告が出るが,一応コンパイルができて実行もできる.

s_char_bit.c:16: 警告: overflow in implicit constant conversion
s_char_bit.c:17: 警告: overflow in implicit constant conversion

実行結果は次のようになる. ここで,数値が負の時には最高位(左端)ビットが 1 であることに注意しよう. このように,符号付きの型の最高位ビットは,その符号を表すので,符号ビットと呼ばれる.

 126  7e  01111110
 127  7f  01111111
-128  80  10000000
-127  81  10000001
  -3  fd  11111101
  -2  fe  11111110
  -1  ff  11111111
   0  00  00000000
   1  01  00000001
   2  02  00000010
   3  03  00000011
 126  7e  01111110
 127  7f  01111111
-128  80  10000000
-127  81  10000001

ところで,-130, -129 と負の方向に範囲を逸脱すると,その値は 126, 127 となり, 128, 129 と正の方向に範囲を逸脱すると,その値は -128, -127 となることにも注意しよう.

このように,符号付き char 型の値が,それが表すことのできる範囲を超えてしまった場合, -128, -127, ..., 126, 127 の繰り返しとなる.

符号付き int の場合も同様に, -2147483648, ..., 2147483647 の繰り返しとなる.

符号付きの型においては,すべてのビットの0と1との値を入れ替えるビット反転という操作で,正の数と負の数とは次のように対応している.

符号付き整数のビット反転での対応表
0 1 2 3 ... 124 125 126 127
00000000 00000001 00000010 00000011 ... 01111100 01111101 01111110 01111111
11111111 11111110 11111101 11111100 ... 10000011 10000010 10000001 10000000
-1 -2 -3 -4 ... -125 -126 -127 -128

普通,正と負とを入れ替えるという操作は,0 を中心にしての反転となるが, 符号付き整数型でビット反転をすると, 0 と -1 の間(すなわち -0.5)を中心としての反転となる. 式で書くと,次の通り.

xをビット反転 = -x-1

種々の整数型

整数値を扱うための型には,( signed, unsigned ) char 型と int 型とがあることは説明したが, それら以外にもある.ここで,まとめて簡単に解説する.

バイト数ビット数最小値最大値
unsigned char180255
signed char18-128127
unsigned short int216065535
signed short int216-3276832767
unsigned int43204294967295
signed int432-21474836482147483647
unsigned long int43204294967295
signed long int432-21474836482147483647
unsigned long long int864018446744073709551615
signed long long int864-92233720368547758089223372036854775807

基本的な整数型には char, short int , int, long int, long long int の4種類があり,そのサイズは char ≦ short int ≦ int ≦ long int ≦ long long int となる.

char 型は 1 バイトであると決まっているが,あとの種類はサイズが厳密に決められたものではなく, 将来は変わる可能性がある. 実際に,数年前のパソコンは 16ビットマシンが多かったので, int 型は 16ビット=2バイトであった.

今使っているコンピュータの環境では,たまたま int 型と long int 型とは,まったく同じものとなっている.

ページ先頭に戻る

ビット演算子

整数型の値を表すビットを,直接操作するための,ビット演算子と呼ばれる種類のものが6個ある. それらは4個のビット論理演算子と2個のシフト演算子に類別される.

ビット論理演算子

ビット論理演算子は,対応する位置のビットごとに操作を施した結果を返す.

ビット論理積 &

A B A & B
0 0 0
0 1 0
1 0 0
1 1 1

& はビット論理積(AND)演算子である. 二つの整数値 a, b に対して, a & b は対応するビットごとに論理積 (AND) をとった結果を返す.

1ビットの値 A, B に対する A & B の値は右の表の通り.

& 演算子は,いくつかに限定したビットの状態だけを取り出したいときに,よく使われる. たとえば,char 型 8 ビットのうち,下位の 4 ビットだけの状態を取り出すならば, 00001111(2) = 15 = 0f(16) とのビット論理積をとればよい. 次の例では, x = 0x6a = 01101010(2) の下位4ビットの値 0x0a = 10 = 00001010(2) の値を取り出している.

int main()
{
  unsigned char x, y, z;

  x = 0x6a;
  y = 0x0f;
  z = x & y;

  show_unsigned_char(x);
  show_unsigned_char(y);
  show_unsigned_char(z);
  
  return 0;
}
 106  6a  01101010
  15  0f  00001111
  10  0a  00001010

また, x = x & y の代わりに x &= y と書くこともできる.

  x &= y;            /* x = x&y と同じ */
サンプルプログラム1

次の関数は引数 x を 2 で割ったときの余りを返す.

int remainder2(int x)
{
  return x & 1;
}

1 は 0000...0001 であるから,x & 1 は x の最下位ビットの値に等しい.それが x を 2 で割ったときの余りである.

演習問題1

引数 x を 8 で割ったときの余りを返す関数 remainder8(x) を, & 演算子を用いて作れ.

int remainder8(int x)
{
    ....
}

ヒント: 8 で割ったときの余りは,下位3ビットが表す値に等しい.

ビット論理和 |

A B A | B
0 0 0
0 1 1
1 0 1
1 1 1

| はビット論理和(OR)演算子である. 二つの整数値 a, b に対して, a | b は対応するビットごとに論理和 (OR) をとった結果を返す.

1ビットの値 A, B に対する A | B の値は右の表の通り.

| 演算子は,いくつかに限定したビットの状態を 1 にセットしたものを得たいときに,よく使われる. たとえば,char 型 8 ビットのうち,下位の 4 ビットをすべて 1 にセットしたければ, 00001111(2) = 15 = 0f(16) とのビット論理和をとればよい. 次のプログラム中の z = x | y という文では, x = 0x6a = 01101010(2) の下位 4 ビットを 1 にセットしたものを z に代入している.

int main()
{
  unsigned char x, y, z;

  x = 0x6a;
  y = 0x0f;
  z = x | y;

  show_unsigned_char(x);
  show_unsigned_char(y);
  show_unsigned_char(z);
  
  return 0;
}
 106  6a  01101010
  15  0f  00001111
 111  6f  01101111

また, x = x | y の代わりに x |= y と書くこともできる.

  x |= y;            /* x = x|y と同じ */

ビット排他的論理和 ^

A B A ^ B
0 0 0
0 1 1
1 0 1
1 1 0

^ はビット排他的論理和(XOR)演算子である. 二つの整数値 a, b に対して, a ^ b は対応するビットごとに排他的論理和 (XOR) をとった結果を返す ( ^ はキャレットあるいはハットと読む).

1ビットの値 A, B に対する A ^ B の値は右の表の通り.

^ 演算子は,いくつかに限定したビットの状態を反転させたものを得たいときに,よく使われる. たとえば,char 型 8 ビットのうち,下位の 4 ビットを反転したければ, 00001111(2) = 15 = 0f(16) とのビット排他的論理和をとればよい. 次の例では, x = 0x6a = 01101010(2) の下位4ビットを反転させたものを z に入れている.

int main()
{
  unsigned char x, y, z;

  x = 0x6a;
  y = 0x0f;
  z = x ^ y;

  show_unsigned_char(x);
  show_unsigned_char(y);
  show_unsigned_char(z);
  
  return 0;
}
 106  6a  01101010
  15  0f  00001111
 101  65  01100101

また, x = x ^ y の代わりに x ^= y と書くこともできる.

  x ^= y;     /* x = x^y と同じ */

排他的論理和は非常に面白い演算であり,次のような性質がある.
(1)  x ^ 0 == x
(2)  x ^ x == 0
(3)  (x ^ y) ^ z == x ^ (y ^ z)
この性質を用いると,簡単な暗号システムが作れる.

数値 x を鍵 k で暗号化したければ,x と k とのビット排他的論理和をとり
   y = x ^ k;
とする.これを復号化したければ,もう一度 k とのビット排他的論理和をとる.
   z = y ^ k;
このとき,z の値は x の値に等しい.なぜならば,
   z == y ^ k == (x ^ k) ^ k == x ^ (k ^ k) == x ^ 0 == x
だからである.

ビット反転 ~

A ~A
0 1
1 0

~ はビット反転演算子あるいはビット否定(NOT)演算子である. 整数値 a に対して, ~a は対応するビットごとにそれを反転した結果を返す. (~ はチルダーと読む)

1ビットの値 A に対する ~A の値は右の表の通り.

~ 演算子は,いくつかに限定したビットだけが 0 で, その他のすべてのビットが 1 であるような値を得たいときに,よく使われる. たとえば,下位の3ビットだけが 0 で残りのビットが 1 であるような整数値 111...111000(2) は 000...000111(2) = 7 に対して ~ を施すと得られる. (その利点は,全体が何ビットあるかを知らなくてもよいということである.)

int main()
{
  unsigned char x, y;

  x = 7;
  y = ~x;

  show_unsigned_char(x);
  show_unsigned_char(y);
  
  return 0;
}
   7  07  00000111
 248  f8  11111000

コンピュータの環境によっては,~ という文字がオーバースコア  ̄ となることもある.

シフト演算子

整数値を表すビットは,2進数表記と同じように,横に一列に並んでいると見なされている. 右端が最下位ビットであり,左端が最上位ビットである.

このビットパターンを,横にずらすことをシフトという. 特に左にずらすことを左シフト,右にずらすことを右シフトという.

左シフト演算子 <<

整数値 a と n とに対して, a << n は a を表すビットパターンを左に n ビットだけずらして得られる整数値を返す. ただし,左にずらしたときに右側に空くビットには 0 が入る.

次の例は, 11 = 00001011(2) を左シフトして得られる値を順に表示している.

int main()
{
  unsigned char x = 11;

  show_unsigned_char(x);
  show_unsigned_char(x << 1);
  show_unsigned_char(x << 2);
  show_unsigned_char(x << 3);
  show_unsigned_char(x << 4);
  show_unsigned_char(x << 5);
  show_unsigned_char(x << 6);
  show_unsigned_char(x << 7);
  show_unsigned_char(x << 8);
  
  return 0;
}
  11  0b  00001011
  22  16  00010110
  44  2c  00101100
  88  58  01011000
 176  b0  10110000
  96  60  01100000
 192  c0  11000000
 128  80  10000000
   0  00  00000000

最初のうちは, 11, 22, 44, 88, 176 と数値が倍々に増えていることに注意しよう. しかし,最上位ビットが1になってそれがさらに左にシフトされて押し出されると, 値が下がってしまう.最後はすべてのビットが左に押し出されて, 0 になってしまう.

シフト演算子は,変数自身の値を変化させるわけではないので,変数 x の値をシフトして変化させたければ x = x << n; あるいは x <<= n; とする必要がある.

  x <<= n;          /* x = x << n と同じ */

右シフト演算子 >>

整数値 a と n とに対して, a >> n は a を表すビットパターンを右に n ビットだけずらして得られる整数値を返す.

この演算子は,符号無しの数値に施したときと符号付きの数値に施したときとで, その結果が異なる.

符号無しの型の場合

左シフトのときと同様に,右にビットパターンをずらしたときに左側に空いたビットには 0 が入る.

このようなシフトを論理シフトと呼ぶこともある.

次の例は, 160 = 10100000(2) を右シフトして得られる値を順に表示している.

int main()
{
  unsigned char x;

  x = 160;
  show_unsigned_char(x);
  show_unsigned_char(x >> 1);
  show_unsigned_char(x >> 2);
  show_unsigned_char(x >> 3);
  show_unsigned_char(x >> 4);
  show_unsigned_char(x >> 5);
  show_unsigned_char(x >> 6);
  show_unsigned_char(x >> 7);
  show_unsigned_char(x >> 8);
  
  return 0;
}
 160  a0  10100000
  80  50  01010000
  40  28  00101000
  20  14  00010100
  10  0a  00001010
   5  05  00000101
   2  02  00000010
   1  01  00000001
   0  00  00000000

160, 80, 40, ... と,1つ右にシフトするごとに数値が約半分, 正確には 1/2倍して端数は切り捨てになっていることに注意しよう. 最後はすべてのビットが右に押し出されて, 0 になってしまう.

シフト演算子は,変数自身の値を変化させるわけではないので,変数 x の値をシフトして変化させたければ x = x >> n; あるいは x >>= n; とする必要がある.

  x >>= n;          /* x = x >> n と同じ */
符号付きの型の場合

符号付き整数型の場合,右にビットパターンをずらしたときに左側に空いたビットには 符号ビット(一番左側のビット)と同じ値が入る.

このようなシフトを算術シフトと呼ぶこともある.

次の例は, 100 = 01100100(2) と -100 = 10011100(2) とに対して,それらを右シフトして得られる値を順に表示している.

int main()
{
  unsigned char x;

  x = 100;
  show_signed_char(x);
  show_signed_char(x >> 1);
  show_signed_char(x >> 2);
  show_signed_char(x >> 3);
  show_signed_char(x >> 4);
  show_signed_char(x >> 5);
  show_signed_char(x >> 6);
  show_signed_char(x >> 7);

  printf("\n");
  
  x = -100;
  show_signed_char(x);
  show_signed_char(x >> 1);
  show_signed_char(x >> 2);
  show_signed_char(x >> 3);
  show_signed_char(x >> 4);
  show_signed_char(x >> 5);
  show_signed_char(x >> 6);
  show_signed_char(x >> 7);
  
  return 0;
}
 100  64  01100100
  50  32  00110010
  25  19  00011001
  12  0c  00001100
   6  06  00000110
   3  03  00000011
   1  01  00000001
   0  00  00000000
   
-100  9c  10011100
 -50  ce  11001110
 -25  e7  11100111
 -13  f3  11110011
  -7  f9  11111001
  -4  fc  11111100
  -2  fe  11111110
  -1  ff  11111111

x が正の値のときには,符号無しの型のときと同様に左側に空いたビットには 0 が入るが, x が負の値の時には,左側に空いたビットには 1 が入る. どちらにせよ,一つシフトするごとに値が 1/2倍(端数は切り下げ)になることに注意しよう.

シフトを続けると,x が正の数のときには,すべてが右に押し出されて 0 となるが, x が負の値のときには,全てが符号ビットで埋め尽くされて -1 となる.

右シフトで左側にあいたビットを符号ビットの値で埋める理由は, 始めの値と同じ符号を持たせるためである. それゆえ,算術シフトと呼ばれる.

シフト演算子は,変数自身の値を変化させるわけではないので,変数 x の値をシフトして変化させたければ x = x >> n; あるいは x >>= n; とする必要がある.

  x >>= n;          /* x = x >> n と同じ */

ビット演算子の優先順位

1 ~
2 << >>
3 &
4 ^
5 |

異なる種類のビット演算子を一つの式の中に使った場合,その優先順位は右の表のようになる (1 が高くて 5 が低い).

例えば, a | b & c という式は a | (b & c) と同じであり, 次の2つの式も同じである.

  f = a | b & ~ c << d ^ e;
  f = a | ((b & ((~ c) << d)) ^ e);

ビット演算子は int 型が主

以上では,ビット演算子を説明するのに char 型で説明してきたが,ビット演算子は主に int 型に 対して働くように設計されている.実は, char 型は大きさが中途半端でビット演算子 (特にシフト演算子)がうまく働かない場合がある.そこで,これ以降は, int 型に対して施すことにする.

まず, unsigned int 型のビット状態を表示する関数を作って, ビット演算子をいくつか試して見てみよう.

#include <stdio.h>

void show_unsigned_int(unsigned int x)
{
  int i;

  printf("%10u  %08x  ", x, x);
  for (i = 31; i >= 0; i--) {
    printf("%d", (x>>i) & 1);
  }
  printf("\n");
}

int main()
{
  unsigned int x = 0x0000ffff;

  show_unsigned_int( x );
  show_unsigned_int( x << 8 );
  show_unsigned_int( x & (x << 8) );
  show_unsigned_int( x ^ (x << 8) );
  show_unsigned_int( ~ (x ^ (x << 8)) );

  return 0;
}
     65535  0000ffff  00000000000000001111111111111111
  16776960  00ffff00  00000000111111111111111100000000
     65280  0000ff00  00000000000000001111111100000000
  16711935  00ff00ff  00000000111111110000000011111111
4278255360  ff00ff00  11111111000000001111111100000000

演習問題2

ビット演算子を用いたクイズです.

先ほどのプログラムのように, 数値 0x0000ffff (=00000000000000001111111111111111(2))が入った変数 x と ビット演算子とを用いて, 次のような結果になるようにせよ. (シフト演算子のシフト量を指定する数値以外は,数値を用いてはならない. 式中の演算子の個数と変数 x の個数とができるだけ少ないようにせよ.)

     98304  00018000  00000000000000011000000000000000
 268435440  0ffffff0  00001111111111111111111111110000
1056964860  3f0000fc  00111111000000000000000011111100
 267390960  0ff00ff0  00001111111100000000111111110000

ページ先頭に戻る

レポート課題

次のプログラムにある show_bit_figure という関数と,ビット演算子とを用いて, ビットで好きなようにアートを作れ. プログラムのサンプルを書いておいたが,それにとらわれず自由に作ってもよい.

#include <stdio.h>

void show_bit_figure(unsigned int x)
{
  int i;

  printf("%10u  %08x  ", x, x);
  for (i = 31; i >= 0; i--) {
    if((x>>i) & 1 == 1) {
      printf(" o");
    } else {
      printf(" .");
    }
  }
  printf("\n");
}

int main()
{
  int i;

  for (i = 0; i < 32; i++) {
    show_bit_figure( ((0x80000000 >> i) | (0x00000001 << i)) ^ 0xff0000ff );
  }

  printf("\n");
  for (i = 0; i < 32; i++) {
    show_bit_figure( (0x0000ffff << (i % 16)) ^ (0xffff0000 >> (i % 16)) );
  }

  return 0;
}
2130706686  7f0000fe   . o o o o o o o . . . . . . . . . . . . . . . . o o o o o o o .
3204448509  bf0000fd   o . o o o o o o . . . . . . . . . . . . . . . . o o o o o o . o
3741319419  df0000fb   o o . o o o o o . . . . . . . . . . . . . . . . o o o o o . o o
4009754871  ef0000f7   o o o . o o o o . . . . . . . . . . . . . . . . o o o o . o o o
4143972591  f70000ef   o o o o . o o o . . . . . . . . . . . . . . . . o o o . o o o o
4211081439  fb0000df   o o o o o . o o . . . . . . . . . . . . . . . . o o . o o o o o
4244635839  fd0000bf   o o o o o o . o . . . . . . . . . . . . . . . . o . o o o o o o
4261412991  fe00007f   o o o o o o o . . . . . . . . . . . . . . . . . . o o o o o o o
4286579199  ff8001ff   o o o o o o o o o . . . . . . . . . . . . . . o o o o o o o o o
4282385151  ff4002ff   o o o o o o o o . o . . . . . . . . . . . . o . o o o o o o o o
4280288511  ff2004ff   o o o o o o o o . . o . . . . . . . . . . o . . o o o o o o o o
4279240959  ff1008ff   o o o o o o o o . . . o . . . . . . . . o . . . o o o o o o o o
4278718719  ff0810ff   o o o o o o o o . . . . o . . . . . . o . . . . o o o o o o o o
4278460671  ff0420ff   o o o o o o o o . . . . . o . . . . o . . . . . o o o o o o o o
4278337791  ff0240ff   o o o o o o o o . . . . . . o . . o . . . . . . o o o o o o o o
4278288639  ff0180ff   o o o o o o o o . . . . . . . o o . . . . . . . o o o o o o o o
4278288639  ff0180ff   o o o o o o o o . . . . . . . o o . . . . . . . o o o o o o o o
4278337791  ff0240ff   o o o o o o o o . . . . . . o . . o . . . . . . o o o o o o o o
4278460671  ff0420ff   o o o o o o o o . . . . . o . . . . o . . . . . o o o o o o o o
4278718719  ff0810ff   o o o o o o o o . . . . o . . . . . . o . . . . o o o o o o o o
4279240959  ff1008ff   o o o o o o o o . . . o . . . . . . . . o . . . o o o o o o o o
4280288511  ff2004ff   o o o o o o o o . . o . . . . . . . . . . o . . o o o o o o o o
4282385151  ff4002ff   o o o o o o o o . o . . . . . . . . . . . . o . o o o o o o o o
4286579199  ff8001ff   o o o o o o o o o . . . . . . . . . . . . . . o o o o o o o o o
4261412991  fe00007f   o o o o o o o . . . . . . . . . . . . . . . . . . o o o o o o o
4244635839  fd0000bf   o o o o o o . o . . . . . . . . . . . . . . . . o . o o o o o o
4211081439  fb0000df   o o o o o . o o . . . . . . . . . . . . . . . . o o . o o o o o
4143972591  f70000ef   o o o o . o o o . . . . . . . . . . . . . . . . o o o . o o o o
4009754871  ef0000f7   o o o . o o o o . . . . . . . . . . . . . . . . o o o o . o o o
3741319419  df0000fb   o o . o o o o o . . . . . . . . . . . . . . . . o o o o o . o o
3204448509  bf0000fd   o . o o o o o o . . . . . . . . . . . . . . . . o o o o o o . o
2130706686  7f0000fe   . o o o o o o o . . . . . . . . . . . . . . . . o o o o o o o .

4294967295  ffffffff   o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
2147385342  7ffe7ffe   . o o o o o o o o o o o o o o . . o o o o o o o o o o o o o o .
1073496060  3ffc3ffc   . . o o o o o o o o o o o o . . . . o o o o o o o o o o o o . .
 536354808  1ff81ff8   . . . o o o o o o o o o o . . . . . . o o o o o o o o o o . . .
 267390960  0ff00ff0   . . . . o o o o o o o o . . . . . . . . o o o o o o o o . . . .
 132122592  07e007e0   . . . . . o o o o o o . . . . . . . . . . o o o o o o . . . . .
  62915520  03c003c0   . . . . . . o o o o . . . . . . . . . . . . o o o o . . . . . .
  25166208  01800180   . . . . . . . o o . . . . . . . . . . . . . . o o . . . . . . .
         0  00000000   . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  25166208  01800180   . . . . . . . o o . . . . . . . . . . . . . . o o . . . . . . .
  62915520  03c003c0   . . . . . . o o o o . . . . . . . . . . . . o o o o . . . . . .
 132122592  07e007e0   . . . . . o o o o o o . . . . . . . . . . o o o o o o . . . . .
 267390960  0ff00ff0   . . . . o o o o o o o o . . . . . . . . o o o o o o o o . . . .
 536354808  1ff81ff8   . . . o o o o o o o o o o . . . . . . o o o o o o o o o o . . .
1073496060  3ffc3ffc   . . o o o o o o o o o o o o . . . . o o o o o o o o o o o o . .
2147385342  7ffe7ffe   . o o o o o o o o o o o o o o . . o o o o o o o o o o o o o o .
4294967295  ffffffff   o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
2147385342  7ffe7ffe   . o o o o o o o o o o o o o o . . o o o o o o o o o o o o o o .
1073496060  3ffc3ffc   . . o o o o o o o o o o o o . . . . o o o o o o o o o o o o . .
 536354808  1ff81ff8   . . . o o o o o o o o o o . . . . . . o o o o o o o o o o . . .
 267390960  0ff00ff0   . . . . o o o o o o o o . . . . . . . . o o o o o o o o . . . .
 132122592  07e007e0   . . . . . o o o o o o . . . . . . . . . . o o o o o o . . . . .
  62915520  03c003c0   . . . . . . o o o o . . . . . . . . . . . . o o o o . . . . . .
  25166208  01800180   . . . . . . . o o . . . . . . . . . . . . . . o o . . . . . . .
         0  00000000   . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  25166208  01800180   . . . . . . . o o . . . . . . . . . . . . . . o o . . . . . . .
  62915520  03c003c0   . . . . . . o o o o . . . . . . . . . . . . o o o o . . . . . .
 132122592  07e007e0   . . . . . o o o o o o . . . . . . . . . . o o o o o o . . . . .
 267390960  0ff00ff0   . . . . o o o o o o o o . . . . . . . . o o o o o o o o . . . .
 536354808  1ff81ff8   . . . o o o o o o o o o o . . . . . . o o o o o o o o o o . . .
1073496060  3ffc3ffc   . . o o o o o o o o o o o o . . . . o o o o o o o o o o o o . .
2147385342  7ffe7ffe   . o o o o o o o o o o o o o o . . o o o o o o o o o o o o o o .

ページ先頭に戻る