★ビット演算(論理演算2)★


では、論理演算の使い道を考えながら続きを説明します。

今回は「フラグ」について書きましょう。

これまでフラグを使ったプログラムをいくつか書いてきました。

フラグにはint型の変数を使っていましたが、2進数で見るとあることに気が付きます。

int型は(私の環境では)32ビットです。

int flag = 0;

として、変数flagを2進数にすると、

  0000 0000 0000 0000 0000 0000 0000 0000

となります。

フラグは「0」と「1」で色々な状態を表すために使われますが、2進数で見ると最下位ビットしか使っていません。

  0000 0000 0000 0000 0000 0000 0000 0000

残りの31ビットは全く使っていないのです。

メモリの容量がシビアな環境だと、非常に無駄な事だと言えます。

残りの31ビットも「0」と「1」が表現できるのですから、int型変数1つで32個のフラグが使えるのと同じことです。

そこで、ビット単位で演算が出来る論理演算の出番です。


フラグのビットを1にする


32ビットは長すぎるので、8ビットで考えます。

とりあえず、↓のプログラムを作ってください。

<sample program 178-01>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x00;

    printf("flag = %02X\n", flag);

    return 0;
}

<実行結果>

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

  %02X

とは、

  16進数2桁で表示する

  1桁の場合は前に0を付ける

という意味になります。

現在のflagの中身を2進数で表現すると、

  0000 0000

となります。

これを8個のフラグと見立てます。

右から0番フラグ、1番フラグと数えることにしますので、

 7654 3210 番
  0000 0000

となります。

ここで、3番フラグを1にするにはどうすれば良いでしょうか?


3番フラグの場所は、10進数で言うと「8」の位に当たります。

そこで、次のようなプログラムを組むと3番フラグが1になります。

<sample program 178-02>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x00;

    flag = 8;

    printf("flag = %02X\n", flag);

    return 0;
}

<実行結果>

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

16進数の「08」は2進数で、

  0000 1000

ですから、3番フラグが1になりました。


しかし、これでは分かりづらいですよね。

7番フラグを1にしようとすると、

flag = 128

と書かなければなりません。

しかも、1ビットごとにフラグとして扱うため、3番フラグが1の時に7番フラグも1にしようとすると、次のようなプログラムになります。

<sample program 178-03>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x00;

    flag = 8;

    flag += 128;

    printf("flag = %02X\n", flag);

    return 0;
}

<実行結果>

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

16進数の「88」は2進数で、

  1000 1000

ですから、7番フラグも1になりました。


この考え方は、論理演算を使うともう少し楽になります。

今回使う論理演算は「論理和:or演算」です。

前回説明したとおり「論理和」は、

  1と1をor演算すると1になります。

  1と0をor演算すると1になります。

  0と0をor演算すると0になります。

という性質を持っています。

0のビットに1をor演算すると、1に変える事が出来ます。

実際にプログラムにしてみましょう。

フラグが0の状態から、3番フラグを1にします。

<sample program 178-04>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x00;

    unsigned char mask = 0x08;

    flag = flag | mask;

    printf("flag = %02X\n", flag);

    return 0;
}

<実行結果>

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

論理演算を行うためのビット列を「マスク」と言います。

このマスクに、ビットを1にしたいところに1を入れたビット列を入れます。

  0x08 → 0000 1000 (3番フラグを1にしたい)

フラグに対して、マスクをor演算することによって、その場所が1になります。

    0000 0000
  | 0000 1000
  -----------
    0000 1000

続いて、7番フラグも1にしたい場合は次のようにします。

<sample program 178-05>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x00;

    unsigned char mask = 0x08;

    flag = flag | mask;

    mask = 0x80;

    flag = flag | mask;

    printf("flag = %02X\n", flag);

    return 0;
}

<実行結果>

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

マスクの内容を変えて、同じ演算をするだけです。

flag = flag | mask;

は、

flag |= mask;

と書く事も出来ますので、これからはこう書きましょう。

※ビットを1にすることを「ビットを立てる」という表現もあります。


フラグのビットを調べる


フラグの該当ビットを1にする方法は分かりましたが、そのビットが1かどうかはどうやって調べるのでしょうか?

これは、「論理積:and演算」を使います。

「論理積」は、

  1と1をor演算すると1になります。

  1と0をor演算すると0になります。

  0と0をor演算すると0になります。

という性質を持っています。

1と1の時だけ、結果が1になるのです。

調べたいビットに1を入れたマスクを作りand演算してみます。

結果は別の変数に入れて確認します。

<sample program 178-06>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x46;

    unsigned char mask = 0x02;

    unsigned char result;

    result = flag & mask;

    printf("result = %02X\n", result);

    return 0;
}

<実行結果>

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

  0x46 → 0100 0110

  0x02 → 0000 0010

1番フラグが1かどうか調べています。

    0100 0110
  & 0000 0010
  -----------
    0000 0010

結果は2となりましが、これで何が分かるのでしょうか?

データを変えて、1番ビットが0のケースを確認してみます。

<sample program 178-07>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x44;

    unsigned char mask = 0x02;

    unsigned char result;

    result = flag & mask;

    printf("result = %02X\n", result);

    return 0;
}

<実行結果>

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

  0x44 → 0100 0100

  0x02 → 0000 0010

1番フラグを調べています。

    0100 0100
  & 0000 0010
  -----------
    0000 0000

and演算はお互いが1の時しか1になりません。

結果を見ると「0」になっています。

演算した結果が0の場合は、該当フラグが1では無かったということです。


フラグのビットを0にする


最後に、該当ビットを0にする方法を書きます。

これには、「排他的論理和:xor演算」を使います。

「排他的論理和」は、

  1と1をor演算すると0になります。

  1と0をor演算すると1になります。

  0と0をor演算すると0になります。

という性質を持っています。

お互い異なる値の時だけ結果が1になり、同じ値の時は0になるのです。

これを使ってビットを0にしてみます。

<sample program 178-08>

#include <stdio.h>

int main(void)
{
    unsigned char flag = 0x67;

    unsigned char mask = 0x04;

    unsigned char result;

    result = flag ^ mask;

    printf("result = %02X\n", result);

    return 0;
}

<実行結果>

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

  0x67 → 0110 0111

  0x04 → 0000 0100

2番フラグを0にしようとしています。

    0110 0111
  ^ 0000 0100
  -----------
    0110 0011

どうでしょうか、ちゃんと2番フラグだけ0になりました。

後々説明するシフト演算と組み合わせるともっと楽に組めるようになります。


次へ

戻る

目次へ