★ビット演算(論理演算とシフト演算)★


ビット演算の最後として、論理演算とシフト演算を組み合わせたプログラムを作ってみましょう。


2進数の表示


最初の題材は2進数表示です。

C言語ではprintf関数を使って8進、10進、16進表示は出来ますが、2進表示は出来ません。

ビット演算の時には2進表示が出来た方が分かりやすい場合もありますので作りましょう。


方法はいくつもありますが、その内の1つを作ってみます。

まず、データとして、

char data = -32;

を用意します。

2進数で書くと、

  1110 0000

です。

実行結果は↑と同じように出力したいので、最上位ビットから1桁ずつ表示することにしましょう。

最上位ビットが1かどうか調べるためにマスクを用意します。

  1000 0000

元のデータとand演算することによって、最上位ビットが1かどうか判断出来ます。

最上位ビットが1の場合は「 "1" 」を、0の場合は「 "0" 」を表示します。

次に、マスクを右へ1ビットシフトし、元のデータとand演算します。

これを繰り返す事で、最上位(左)から最下位(右)ビットまで調べる事が出来ます。

8ビットですから、8回繰り返せばOKです。

<sample program 181-01>

#include <stdio.h>

#define BIT_COUNT 8

int main(void)
{
    char data = -32;

    unsigned char mask = 0x80;

    int i;

    for (i = 0; i < BIT_COUNT; i++) {

        if (data & mask) {
            printf("1");
        }
        else {
            printf("0");
        }

        mask >>= 1;
    }

    printf("\n");

    return 0;
}

<実行結果>

11100000
続行するには何かキーを押してください・・・

上手く動きましたが、結果の表示が見難いです。

今まで4桁で区切ってきましたので、同じようになるよう工夫しましょう。

<sample program 181-02>

#include <stdio.h>

#define BIT_COUNT 8

int main(void)
{
    char data = -32;

    unsigned char mask = 0x80;

    int i;

    for (i = 0; i < BIT_COUNT; i++) {

        if (i != 0 && i % 4 == 0) {
            printf(" ");
        }

        if (data & mask) {
            printf("1");
        }
        else {
            printf("0");
        }

        mask >>= 1;
    }

    printf("\n");

    return 0;
}

<実行結果>

1110 0000
続行するには何かキーを押してください・・・

これで4桁ずつ区切って表示する事が出来ました。

追加したif文の最初の条件

i != 0

が無ければ、一番最初に空白が1つ入ってしまいます。


任意のビット列の取り出し


今度は、任意のビット列の取り出し、というのをやってみましょう。

今回取り扱う数値は「色」です。

最近はパソコンの性能も上がり、余り気にする事では無くなっていますが、昔は気を使わなければならない事でした。

今は使われることが無いかもしれませんが、1つの色を16ビットで扱う形式があります。

各ビットの意味は次の通りです。

   15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  |赤|赤|赤|赤|赤|緑|緑|緑|緑|緑|緑|青|青|青|青|青|
  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  第0ビット〜第4ビット 青色の情報 0〜31
  第5ビット〜第10ビット 緑色の情報 0〜63
  第11ビット〜第15ビット 赤色の情報 0〜31

※16ビット565形式と言います。

「青」を例に取ると、青が無い状態が0で、真っ青の状態が31、全部で32段階の色調整が出来るというイメージです。

「緑」は人間が知覚しやすいという理由で64段階に分かれています。

これらの3色の組み合わせで、画面の色を決めるのです。

とは言え、グラフィックスは扱えませんから、ビット演算だけやります。 


例えば次のような色を作りたいと思います。

 「青」 18
 「緑」 42
 「赤」 24

それぞれ、ビットにすると

 「青」  10010
 「緑」 101010
 「赤」 11000

ですから、

565形式にすると、

 11000 101010 10010

になります。

16進数では、

  1100 0101 0101 0010

 C552

です。

これをプログラムで用意して、ビットの取り出しをやってみましょう。


まずはビット列を用意します。

<sample program 181-03>

#include <stdio.h>

int main(void)
{
    unsigned short color = 0xC552;
    
    return 0;
}

符号なし16ビットは、unsigned short型になります。


このビット列から「青」「緑」「赤」を取り出します。

まずは簡単な「青」から行きましょう。

「青」は下位5ビットに情報が入っています。

下位5ビットだけ取り出すにはand演算を使います。

元データの、

 1100 0101 0101 0010

から、下位5ビットを取り出すためのマスクを用意します。

マスクは、

 0000 0000 0001 1111

こうなります。

実際にand演算をしてみると、

   1100 0101 0101 0010
 & 0000 0000 0001 1111
  ---------------------
    0000 0000 0001 0010

行けそうです。

<sample program 181-04>

#include <stdio.h>

int main(void)
{
    unsigned short color = 0xC552;

    unsigned short blueMask = 0x001F;

    unsigned short blue;

    blue = color & blueMask;

    printf("blue = %d\n", blue);
    
    return 0;
}

<実行結果>

blue = 18
続行するには何かキーを押してください・・・

ちゃんと取り出せました。


次は「緑」です。

「緑」を取り出すマスクは、

 0000 0111 1110 0000

です。

実際にand演算をしてみると、

   1100 0101 0101 0010
 & 0000 0111 1110 0000
  ---------------------
    0000 0101 0100 0000

取り出せたような気がしますが、このままでは「42」にはなりません。

「42」を16ビットのビット列で表すと、

 0000 0000 0010 1010

のはずです。

  0000 0101 0100 0000

 0000 0000 0010 1010

にしようと思えば、右に5ビットシフトすればいけそうです。


では、プログラムを追加しましょう。

<sample program 180-05>

#include <stdio.h>

int main(void)
{
    unsigned short color = 0xC552;

    unsigned short blueMask = 0x001F;

    unsigned short greenMask = 0x07E0;

    unsigned short blue;

    unsigned short green;

    blue = color & blueMask;

    printf("blue = %d\n", blue);

    green = color & greenMask;

    green >>= 5;

    printf("green = %d\n", green);

    return 0;
}

<実行結果>

blue = 18
green = 42
続行するには何かキーを押してください・・・

ここまでの流れが理解できれば「赤」も行けます!

皆さんで作ってみてください。









































解答例です。

<sample program 181-06>

#include <stdio.h>

int main(void)
{
    unsigned short color = 0xC552;

    unsigned short blueMask = 0x001F;

    unsigned short greenMask = 0x07E0;

    unsigned short redMask = 0xF800;

    unsigned short blue;

    unsigned short green;

    unsigned short red;

    blue = color & blueMask;

    printf("blue = %d\n", blue);

    green = color & greenMask;

    green >>= 5;

    printf("green = %d\n", green);

    red = color & redMask;

    red >>= 11;

    printf("red = %d\n", red);

    return 0;
}

<実行結果>

blue = 18
green = 42
red = 24
続行するには何かキーを押してください・・・

最後に課題を出しましょう。

<sample program 181-07>

#include <stdio.h>

int main(void)
{
    unsigned short color = 0x0000;

    unsigned short blue = 18;

    unsigned short green = 42;

    unsigned short red = 24;

    /* ここにプログラムを追加する */

    printf("color = %04X\n", color);

    return 0;
}
 「青」 18
 「緑」 42
 「赤」 24

から、16ビット565形式の色情報を作ることが出来ますか?









































解答例です。

<sample program 181-08>

#include <stdio.h>

int main(void)
{
    unsigned short color = 0x0000;

    unsigned short blue = 18;

    unsigned short green = 42;

    unsigned short red = 24;

    color = (red << 11) | (green << 5) | blue;

    printf("color = %04X\n", color);

    return 0;
}

<実行結果>

color = C552
続行するには何かキーを押してください・・・

簡単なプログラムを作る上で、ビット演算を使わなくても済むケースがほとんどです。

しかし、知っていると色々な問題を解決することが出来る可能性があります。

無理に使う必要はありませんが、使えると非常に便利です。


次へ

戻る

目次へ