◆◆◆◆アマゾンで購入する◆◆◆

12.ビット演算 
           内    容
(1)確認用プログラムの準備
(2)基本的なビット演算
(3)ビット単位の左シフト
(4)ビット単位の右シフト
(5)ビット列表示の改良
(6)演習


(1)確認用プログラムの準備

ビット演算とは,
データを1ビットずつ処理する演算ですが,
これまで出てきた加算・減算などの演算にくらべ,
なじみのない方が多いかもしれません。

しかし,
ひとつの命令をフィールドに分けたり,
特定のビットを判定するには,
必要不可欠な演算です。

当然,システム記述用言語としては,
これらの操作ができなくてはいけません。

しかし,なじみがない方のほうが多いと思います。

そのような方は,
演算結果をビットごとに確認するプログラムを
先につくってしまいましょう。

このプログラムは
ビット構造体や共用体の例でもありますので,
ぜひ,例題として保存しておくことを
お勧めします。

  [ビット演算確認用プログラム]
#include "stdafx.h"
#include "string.h"

/*(1)ビットフィールド構造体*/
struct bitdata
{
 unsigned b7:1;
 unsigned b6:1;
 unsigned b5:1;
 unsigned b4:1;
 unsigned b3:1;
 unsigned b2:1;
 unsigned b1:1;
 unsigned b0:1;
};

/*(2)演算子テーブル構造体*/
struct opetab
{
 char name[4];
 int num;
};

/*(3)演算子テーブル定義*/
static struct opetab tab[7]
={{"" ,0},{">>",2},{"<<",2},
 {"&",2}, {"|",2},{"^",2},
  {"~",1}};

/*(4)文字とビットフィールドの領域の共有*/

union uxd
{
 char ch;
 struct bitdata bt;
};

/* 1ビット表示 */
void print_bit(char ch)
{
 if(ch==0) printf("0");
 else printf("1");
}


/* ビット列表示 */
void print_bitlist(struct bitdata ch)
{
 print_bit(ch.b0);print_bit(ch.b1);
 print_bit(ch.b2);print_bit(ch.b3);
 print_bit(ch.b4);print_bit(ch.b5);
 print_bit(ch.b6);print_bit(ch.b7);
}

/* 演算子テーブル探索*/
int table_search(int num,struct opetab tab[])
{
 int i; i=num-1;
 while(strcmp(tab[i].name,tab[0].name)!=0) i--;
 return i;
}


/* 演算用データ入力*/
void data_in(int num,int dt[])
{
 int i;union uxd r;
 for(i=0;i<num;i++)
 {
  printf("\nデータを16進2桁で入力(%d)=",i+1);
  scanf("%x",&dt[i]);
  printf(" 演算用データ:");
  r.ch=dt[i];print_bitlist(r.bt);
 }
}

/* 演算子入力*/
void ope_in(char ch[])
{
 printf("\n演算子入力:");
 scanf("%s",ch);
}

/* 結果表示*/
void print_result(struct bitdata r)
{
 printf("\n\n 結 果=");
 print_bitlist(r);
 printf("\n");
}


/* 演算実行*/
int exec_op(int id,int dt[])
{
 switch(id)
 {
  case 1 : return(dt[0] >> dt[1]);
  case 2 : return(dt[0] << dt[1]);
  case 3 : return(dt[0] & dt[1]);
  case 4 : return(dt[0] | dt[1]);
  case 5 : return(dt[0] ^ dt[1]);
  case 6 : return( ~ dt[0]);
  default: return 0;
 }
}


/* メイン*/
int main(int argc, char* argv[])
{
 int id; int dt[2];union uxd r;
 ope_in(tab[0].name);
 while(strcmp(tab[0].name,"end") !=0)
 {
  id=table_search(7,tab);
  if(id != 0)
  {
   data_in(tab[id].num,dt);
   r.ch=exec_op(id,dt);
   print_result(r.bt);
  }
  else printf("**演算子の誤り\n");
  ope_in(tab[0].name);
 }
}

(2)基本的なビット演算

1ビットのデータA,Bに対する基本的な演算を
下表に示します。

A B A & B A | B A ^ B ~ A
0 0 0 0 0 1
0 1 0 1 1 1
1 0 0 1 1 0
1 1 1 1 0 0
Ope 1 Ope 2 (and) (or) (exor) (not)

これらの演算を使って,
あるビットがオンかオフかの判定,
ビット反転,ビットごとの組合せなどの
処理を行います。

■小演習(1)
基本的なビット演算を準備したプログラムで
確認してみましょう。

(3)ビット単位の左シフト

ビットを左にシフトします。

 0000 0011 ⇒(左に1ビットシフト)⇒ 0000 0110
 (10進数 3)              (10進数 6)

[記述法]

   A << 1    (データ A を左に1ビットシフト)

左シフトは,2n倍の乗算の替わりにも使うことができます。

 シフト 等価な乗算
 A << 1  A * 2
 A << 2  A * 4
 A << 3  A * 8
 A << 4  A * 16
 A << 5  A * 32

■小演習(2)
左シフトを準備したプログラムで確認してみましょう。

(4)ビット単位の右シフト

ビットを右にシフトします。

 0000 00110 ⇒(左に1ビットシフト)⇒ 0000 011
 (10進数 6)              (10進数 3)

[記述法]

   A >> 1    (データ A を右に1ビットシフト)

右は,2n整数による除算の替わりにも使うことができます。

 シフト 等価な除算
 A >> 1  A / 2
 A >> 2  A / 4
 A >> 3  A / 8
 A >> 4  A / 16
 A >> 5  A / 32

なお,符号ビットの取り扱いが,処理系によっては,
次のように異なる場合があります。

●unsignedの場合,
  左端の空いた部分に0が詰められる。 (論理シフト)

●signedの場合,
  最も左端のビットがコピーされる。 (算術シフト)

[算術シフト]
  0000 0110 ⇒(右に1ビットシフト)⇒ 0000 0011
  1100 0110 ⇒(右に1ビットシフト)⇒ 1110 0011

[論理シフト]
  0000 0110 ⇒(右に1ビットシフト)⇒ 0000 0011
  1100 0110 ⇒(右に1ビットシフト)⇒ 0110 0011

しかし,逆にいうと
上記のように処理されない処理系もありますので,
算術シフトを使いたい場合は,
以下のように記述することをお勧めします。

    ( A >> 1) | (A & 0x80)

■小演習(3)
右シフトを準備したプログラムで確認してみましょう。

(5)ビット列表示の改良

準備したプログラムのビット列表示の部分は,
ビットフィールド構造体を使わなくても
シフトを使えば,以下のように短く表現できます。

  #/* もうひとつのビット列表示*/
void print_bitlist_dash(char ch_in)
{
 char ch;int i; ch = ch_in;
 for(i = 0;i < 8; i++, ch <<= 1)
   printf((ch & 0x80)? "1":"0");
}


(6)演習

上記(5)で示したプログラムを用いて,
確認用のプログラムを短く書き直して下さい。

[ヒント]ビットフィールド構造体の宣言および
     charとbitの共用体の宣言は削除します。

 1.C言語の誕生

 2.C言語の仲間たち

 3.新しい言語をすばやく覚えるには

 4.Cでプログラミング

 5.データの入れ物 変数の考え方

 6.注釈・定数

 7.プログラムの実行順序

 8.配列

 9.C言語特有の代入文・制御構造

10.関数の話

11.構造体と共用体

12.ビット演算

13.プログラムの場所をポインタで

14.ファイルの入出力

15.色々な便利な方法