ビット演算のやり方

 マイコンプログラミングには、通常のデータ処理プログラミングではあまり使わないテクニックを使う必要がある。

 マイコンはメモリやIOのデータの読み書きをするためにビット単位での処理を行う事が多い。この様な場合は、ビットシフトビット演算ビットマスクなどを使う。

 ビット演算子とはコンピュータが扱うデータの最小単位である“ビット”を直接操作する演算子のこと。マイコンプログラミングでは1ビット単位でのデータ操作を行うケースが多いため、ビット操作は不可欠。ビット操作には次の操作がある。

  1. ビットのマスク (特定位置ビットの取り出し)
  2. ビット列の合成 (ビット列とビット列を足し合わせる)
  3. ビットのシフト(ビット列をずらす)
     

1.ビットのマスク(特定位置ビットの取り出し)

 ビットのマスクはビット列の中から特定の位置のビットの値を調べるときに使う。例えば、8ビット長のデータ0x97の下位4ビットの状態を調べるには同じ8ビット長の0x0f(ビット列:00001111)とビット毎のAND演算を行う。

 

以上の操作をプログラムで表現すると、

int main()
{
     int   i = 0x97;
     int   j;

     j = i & 0xF;   // 下位4ビット分のマスク
                        // jには下位4ビットのデータが格納される
    printf("%x\n", j);
}

                           図 マスクを使った下位4ビットの取り出し

  ※bit毎のAND演算とは、2進数の各桁毎の掛け算と考えてもよい。


2.ビット列の合成

 4ビット長のデータaと同じく4ビット長のデータbがある。この2つのデータを合成して上位4ビットにa、下位4ビットにbとした8ビット長のデータを作成する。このような操作はマイコンプログラミングでは非常によくある。
 このようなビット列の合成は、ビット毎のOR演算を行うことで求めることができる。 


以上の操作をプログラミングすると、

int main()
{
     int   i = 0x40;
     int   j = 0x03;
     int   k;

     k = i | j;  // ビット列の合成
    printf("%x\n", k);
}

                             図 OR演算によるビット列の合成
 
  ※bit毎のOR演算とは、2進数の各桁毎の加算と考えてもよい。


3.ビットのシフト

 コンピュータ内のデータは2進数のビット列で表現されている。このビット列のビットを左右に“ずらす”ことをビットシフトといい、下表の演算子がある。

 演算子                      意   味    使   用   例                    解      説
    <<   ビットを左にシフト   a = b << 3  bの値を3ビット左シフトし、aに代入
    >>   ビットを右にシフト   a = b >> 2  bの値を2ビット右シフトし、aに代入
    <<=   ビットを左にシフトし、その値を代入   a <<= b  aの値をbの値分、左シフトし、aに代入
    >>=   ビットを右にシフトし、その値を代入   a >>= 3  aの値を3ビット右シフトし、aに代入


■右シフト(論理シフト)
 8ビット長の0x68(001101000)を右に2ビットシフトすると、下図のようになる。
      

■左シフト(論理シフト)
 8ビット長の0x68(001101000)を左に2ビットシフトすると、下図のようになる。

          
以上をプログラムすると、以下のようになる。

int main()
{
     int   i = 0x68;

     k = i >> 2;  // ビット列を右2bitシフト
    printf("%x\n", k);

    k = i << 3;  // ビット列を左3bitシフト
    printf("%x\n", k);
}


■算術シフト(右シフト)
ビット列のシフトを行う際に、符号ビットの値を残してシフトを行う事を、算術シフトと呼ぶ。

0xB4 (-76)を右2bit算術シフトすると、

      

0x34(52)を右2bit算術シフト(=論理シフト)すると、
        

【注意】
 C言語では、どのように記述すると算術シフトになるか・もしくは論理シフトになるかは仕様で明確化されていない。
 したがって、コンパイラ毎に挙動が異なる。

 ちなみにgccでは、変数の型をsigned(符号付き)にすると算術シフト、unsigned (符号なし)にすると論理シフトとなる。
 

最終更新:2016年03月22日 10:06