#pragma twice

KAB-studio > プログラミング > #pragma twice > 234 Version 12.11 パディングとアライメント

#pragma twice 234 Version 12.11 パディングとアライメント

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

 Version 12.11
パディングとアライメント

「前回は複数データの書き込みと読み込みをしてみました」
『 fread() と fwrite() 使ってね』
「でも、データひとつひとつを書き込むっていうのはちょっと面倒、という
わけで今回は構造体を使ってみます」
『あ、構造体丸ごと書き込んだりすれば簡単だもんね』
「そういうこと。でもそこで注意しなきゃいけない点があるから」
『注意点?』
「まずはファイルは抜かして考えようか。 Version 12.01 ( No.224 ) を思
い出して」
『ん……あ、そういえば構造体のサイズってやったね』
「そう。たとえば」

struct TEST_STRUCT
{
    char m_ch;
    int m_i;
};

「って構造体があるとします。このサイズは?」
『 1 + 4 = 5 ……じゃないんだよね』
「そう、答えは 8 」

void SizeOf_TEST_STRUCT()
{
    TRACE( "%d\n", sizeof( TEST_STRUCT ) );
    // 8
}

『謎よねー』
「ではもうひとつ」

struct TEST_STRUCT_DOUBLE
{
    char m_ch;
    double m_d;
};

「の構造体」
『 int じゃなくて double になってる』
「このサイズは、というと」

void SizeOf_TEST_STRUCT_DOUBLE()
{
    TRACE( "%d\n", sizeof( TEST_STRUCT_DOUBLE ) );
    // 16
}

『じゅ、 16 !? なんでそんなに大きいの!? だって、 double って 8 
バイト……あ!』
「はい火美ちゃん」
『もしかして、 double の倍のサイズになってる!? さっきのは int の
倍だし』
「その通り! と、もうひとつ例を見ておこうか」

struct TEST_STRUCT_DOUBLE_2
{
    char m_ch;
    double m_d;
    char m_ch2;
};

『後ろに char が増えた』
「これのサイズはというと」

void SizeOf_TEST_STRUCT_DOUBLE_2()
{
    TRACE( "%d\n", sizeof( TEST_STRUCT_DOUBLE_2 ) );
    // 24
}

『あ”、 24 、ってことは double の3倍?』
「そういうこと」
『……つまり、変数が3つあるから、3倍?』
「ほとんどそうだけど、ちょっと違うかな。正確に言うと、それぞれの変数
に【無駄な部分】が加えられて double と同じサイズになってる、ってとこ
ろかな」
『無駄な部分?』
「この構造体をメモリ上で見てみるとわかるかな」

void Use_TEST_STRUCT_DOUBLE_2()
{
    TEST_STRUCT_DOUBLE_2 stTEST_STRUCT_DOUBLE_2;
    TRACE( "%X\n", &stTEST_STRUCT_DOUBLE_2 );
    // まずは 0xAA で初期化。
    memset
        ( &stTEST_STRUCT_DOUBLE_2
        , 0xAA
        , sizeof( stTEST_STRUCT_DOUBLE_2 ) 
        );
    // 各変数をセット。
    stTEST_STRUCT_DOUBLE_2.m_ch  = 63;
    stTEST_STRUCT_DOUBLE_2.m_d   = 2.0;
    stTEST_STRUCT_DOUBLE_2.m_ch2 = 63;
}

『 memset() って? ランタイムっぽいけど』
「 memset() は、第1引数のアドレスから第3引数バイトまで、第2引数で
埋めるっていうランタイム。 TRACE() で構造体のアドレスを出してるから
それでメモリウィンドウを見てみて」
『ほい。ん? どこで止めて?』
「最初は」

    stTEST_STRUCT_DOUBLE_2.m_ch  = 63;

「で止めて、 memset() の結果を見た方がいいかな」
『ほい。お、全部 AA だ』
「 8 バイト単位で改行するとこうなります」

AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA AA

「今度は、最後の } の所まで進めて」
『構造体にデータ入れ終わる所までね。ほい』

3F AA AA AA AA AA AA AA
00 00 00 00 00 00 00 40
3F AA AA AA AA AA AA AA

『だいぶ変わった』
「まず真ん中の行から見て。これは double だから 8 バイトまるまる使い
ます」
『だから AA がないんだね』
「一方、上下の char は 1 バイトしか使わないので、先頭の 1 バイトにし
かデータが入っていません」
『残りは AA のままなんだ』
「つまり、 char の変数として使っている後ろに、 7 バイトの無駄な領域
があるってこと。この無駄な領域を【パディング】って言います」
『パディング?』
「そう、 padding 、英語で〈詰め物〉って意味」
『なるほど。でもさ、これってホント、無駄じゃん。なんでこんなふうに
なってるの?』
「それは、この方がコンピューターにとっては見やすいから」
『見やすい?』
「 Version 4.08 ( No.058 ) でちょっと触れたけど、 int みたいに、コン
ピューターが処理しやすいサイズがあるんです」
『あ、32ビットだから 4 バイトだと処理しやすい、とかゆーあれね』
「そう。今はひとつの変数が最大 8 バイト単位になるようになっていて、
そうするとコンピューターは 4 の倍数だから処理が楽になるんです」
『そのための無駄ってわけね』
「この、サイズを揃えるっていう仕組みを【アライメント】って言います」
『あらいめんと?』
「 alignment 、〈整列〉って意味」
『確かに並べてるね』
「このアライメントの仕組みがあるから、構造体を作ると自動的にパディン
グが入れられて、サイズが倍数になるんです」
『質問!』
「はい火美ちゃん」
『さっき〈今はひとつの変数が最大 8 バイト単位に〉って言ってたってこ
とは、それって変えられるってこと?』
「そういうこと。これは【プロジェクトの設定】>【C/C++】
>【コード生成】ページの【構造体メンバのアライメント】ってところに」
『 8 バイトって書いてある!』
「これを 1 バイトにしてリビルドして、もう一度試してみて」
『ほい』
「まずサイズを見てみます」

    TRACE( "%d\n", sizeof( TEST_STRUCT_DOUBLE_2 ) );
    // 10 

『 10 ! char + double + char = 1 + 8 + 1 = 10 ?』
「そういうこと。メモリを見てみると、 memset() の直後は」

AA
AA AA AA AA AA AA AA AA
AA

「という感じになってます。その次にデータを入れてみると」

3F
00 00 00 00 00 00 00 40
3F

『うわー、パディングがまるまるなくなってる』
「このように、プロジェクトの設定でアライメントを変えると、構造体の中
身は大きく変わります」
『ここまで変わるんだ……質問!』
「はい火美ちゃん」
『結局、アライメントっていくつがいいの? デフォルトの 8 でいいの?』
「今はコンピューターの性能がかなりいいから、それほど大きな問題じゃな
いかも。 8 でもいいし 1 でもいいし。ただ」
『ただ?』
「今は CPU に比べて、メモリサイズやネットワークの太さのの方が問題に
なることが多いと思うから、そう考えるとパディング 1 の方がいいかも」
『 CPU はどんどん性能上がってるけどメモリとかまだ高いものね……』

/*
    Preview Next Story!
*/
『でも今回ってバイナリーとかあんま関係なくない?』
「実は、ファイルの読み書きが絡んでくると重要になるんです」
『?』
「アライメントを 8 で書き込んで 1 で読み込んだら?」
『あ……』
「というわけで次回」
< Version 12.12 構造体のファイル読み書き >
『につづく!』
「この辺はうっかりバグになりやすいから」
『んーでもホントにうっかりって気が……。』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。