#pragma twice

KAB-studio > プログラミング > #pragma twice > 055 Version 4.05 ビット操作

#pragma twice 055 Version 4.05 ビット操作

前のページへ 表紙・目次へ 次のページへ

 Version 4.05
ビット操作

前回は2進数ってものについて紹介しました
なんかパズルみたいだったよねー
今回は、そのイメージをもっとしっかりしたものにしようと思います。え
っとまず、用語について。ビットって知ってる?
聞いたことはあるけど、よくしんない
ビットって言うのは、2進数で表示したときの〈桁の数〉。だから 00 な
ら2ビットね
あー、じゃー 0101 なら4ビットってこと?
そゆこと。つまり4ビットで16進数1桁ってことだね。さて次。 0001 
を16進数で言うと?
 1 だよ
じゃ 0010 は?
えっと、 2 だね。ついでに言っとくと 0100 は 4 で 1000 は 8 だよ
そうそう、 8421 ってなってるからね。で、 0001 を〈ずらして〉 0010
にすることを〈ビットシフトする〉って言います
びっとしふと?
そう。〈シフト〉っていうのは〈ずらす〉って意味。ビットをずらすわけ
ってことは 0010 をビットシフトすると 0100 になるの?
そゆこと。あと左方向じゃなくて右方向にもシフトできるよ
できるよ、ってのは?
あー、そういうことがプログラムでできるってこと。やってみようか

void BitShiftLeft()
{
    char ch = 0x01; // 00000001
    for( int iF1 = 0; iF1 < 4; iF1++ )
    {
        TRACE( "%X ", ch );
        ch = ch << 1; // ここ。
    }
}
// 1 2 4 8 

むむ、なんか難しそう
ひとつひとつね。まず char 型の変数を作って、 00000001 を入れます
 char って数字入れるのだもんね。で、 for だから繰り返しね
そう、4回繰り返し。繰り返すのは、 ch を16進数として表示するとこ
と、 << 演算子を使うこと
これ初見!
この << を使うと、左方向にビットシフトします
あ、これがさっき言ってた〈できる〉ってことね
 << 演算子は、左の数字を、右の回数だけずらします
この例だと1回だけずらすんだ。2回ずらすって、 0001 が 0100 になる
ってこと?
そういうこと。で、ここでは1回ずつずらしてるから、 ch の中身は 0001
0010 0100 1000 っていうふうにひとつずつずれていくわけ
だから結果が 1 2 4 8 ってことなんだ。でも当たり前よね
そう、そこが大事!
な、なに?
前も言ったけど、ビットそのものを直接見ることはできないわけ
あー、この例だと ch を 0001 みたいに表示できないってことね
そうそう。だから16進数で表示してイメージ沸かせるしかないんだけど
当たり前って思えるんなら、イメージがしっかりできてるってこと?
そういうこと。それが大事だから
ま、こういう例が見られればね
ちなみに今のは左シフト。右シフトは >> を使います

void BitShiftRight()
{
    char ch = 0x08; // 00001000
    for( int iF1 = 0; iF1 < 4; iF1++ )
    {
        TRACE( "%X ", ch );
        ch = ch >> 1; // ここ。
    }
}
// 8 4 2 1 

今度は 1000 0100 0010 0001 ってなってくんだ
そういうこと。じゃ、次に進みます。フラグって知ってる?
ゲームするときにときどき聞くね
フラグっていうのは〈しるし〉のこと。たとえば RPG とかで、ボスを倒
すとストーリーが変化したりするでしょ
よくあるパターンね
こういうとき〈フラグが立った〉って言います。フラグって英語で〈旗〉
って意味。ボスを倒した印として旗が立つ、ってイメージかな
オフサイドぴぴーみたいな?
そういうこと。で、実際にホントに旗が立つわけじゃなくて、プログラム
の中では〈変数の値が変わる〉ってことを印にします
たとえば int の変数作って、 1 ならまだ倒してない、 -1 なら倒した、
みたいな?
そうそう、そういうこと。それをもっと効率良くしたのが〈ビットフラグ〉
ってもの
ビットフラグ?
 0000 の各ビットって、基本的にスイッチでしょ
うんうん
だからたとえば〈一番右の桁が、 0 ならまだ倒してない、 1 なら倒した〉
みたいなフラグにすることができるわけ
 0000 なら倒してない、 0001 なら倒したってことね。でも他の3桁が無
駄じゃん
そこは別のフラグに使えばいいでしょ
あ、つまりこうすれば、 char なら……えっと、8個のフラグが使えるっ
てことなんだ!
そういうこと。これなら効率的でいいでしょ
うん、いいいい。で、どう使うの?
〈ビット和演算子〉ってものを使います
びっとわ? べべんべんべん
そりゃ琵琶や
ぶぶー三味線だもん
分かんないって。で話を戻すと、 1000 と 0001 を組み合わせて 1001 に
したいってときは、どうすればいい?
足せばいいんじゃない? えっと、 8 と 1 だから足して 9 ! うん、
やっぱ足せばいーよね
じゃ、 1001 と 0001 を組み合わせて 1001 にしたいときは?
あれ? 1010 になんないの?
それぞれの桁は別のフラグなんだから、繰り上がりしちゃダメでしょ。も
ともとフラグが立っているときにさらにフラグ立てようとしたら、そのまま
立たせとくってこと
つまり 0001 と 0001 組み合わせても 0001 ってことね。これは足し算
じゃむりね。そこでビット和!
そゆこと。ビット和演算子は | のこと。 Shift キー押しながら Back
Space の左のキーを押せば出てくるから
ほほー、こんなマイナーなものが……
では試してみましょう

void BitSum()
{
    char ch
        = 0x08  // 00001000
        | 0x01; // 00000001
    TRACE( "%X\n", ch );
    // 9
    // つまり 00001001

    ch
        = 0x09  // 00001001
        | 0x01; // 00000001
    TRACE( "%X\n", ch );
    // 9
    // つまり 00001001
}

んーと、 char の変数 ch を作って、数字入れてるね
ここで、 1000 と 0001 を組み合わせた結果を ch の中に入れてます
その〈組み合わせ〉をするのが | ってことね。で結果が 1001
つまり | を使うと特定のビットだけを 1 にすることができます
〈特定のビット〉を変えるときって、 0001 を 0010 や 0100 にすればい
いってことだよね
そういうこと。で、その次に 1001 と 0001 を組み合わせてます
足し算なら 1010 になっちゃうけど、ビット和だから 1001 なんだね
ビット和が各ビットを操作できるってことが分かったね。ちなみにビット
和、実は前に使ったことがあるんだよ
ええっ!? ど、どーりでどっかで見たよーな気が
してないでしょ。 Ver 2.11 ( No.022 )で、こんなふうに使ってます

    MessageBox( "あいうえお", "かきくけこ"
                , MB_YESNO | MB_ICONQUESTION );

あ、これダイアログ表示するのだよね。 MB_YESNO って【はい】と【いい
え】のボタンを付けるので、 MB_ICONQUESTION ってアイコンをはてなマーク
にするのだよね
そうそう。こういう〈状態を渡す〉ときは、たいがいこういうふうにビッ
ト和で渡します
つまり MB_YESNO とかがビットフラグになってるってことね
そういうこと。じゃ、今日最後は、 & について
 & って〈アンド〉だよね
ま、それは考えない方がいいかな。 & もビット操作をする演算子。ま、
とりあえずこれを試してみて

void BitMultiply()
{
    char ch
        = 0x01  // 00000001
        & 0x08; // 00001000
    TRACE( "%X\n", ch );
    // 0

    ch
        = 0x09  // 00001001
        & 0x08; // 00001000
    TRACE( "%X\n", ch );
    // 1
    // 00001000
}

えっと、上は 0 、下は 1 
 & は、ビットが両方とも 1 だと 1 に、それ以外は 0 にするって演算子。
上は、どのビットも合ってないでしょ
あ、下は右から4ビット目が両方とも 1 だから、そこだけが 1 になって
るんだ。でもこれって使えなくない?
これはね、フラグが立ってるか立ってないかをチェックするの

void CheckBitFlag( char p_ch )
{
    if( p_ch & 0x1 )    // 00000001
    {
        TRACE( "赤" );
    }

    if( p_ch & 0x8 )    // 00001000
    {
        TRACE( "青" );
    }
    
    TRACE( "\n" );
}

void SendBitFlag()
{
    CheckBitFlag( 0x1 );
    // 赤
    CheckBitFlag( 0x8 );
    // 青
    CheckBitFlag( 0x1 | 0x8 );
    // 赤青
}

あ、 if って 0 以外だと {} の中に入るんだもんね。 & で立ってるかど
うか調べられるんだ
こうすることで、ひとつの変数にいっぱいのフラグを格納できるってわけ
だね

/*
    Preview Next Story!
*/
でもさ、フラグってホントは〈フラッグ〉じゃないの?
そういえばそうだね……
ねー〈ビットを 0 にする〉のはどうすればいいの?
そんなめったに使わないの憶える必要ないよ……
なんか投げやりー
というわけで次回
< Version 4.06 正と負! >
につづく!
業界には不思議なことが多いしね……
何黄昏てんのよ
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。