#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のトップページをご覧ください。