構造体の大きさとアライメント

C言語の初心者が陥りやすい罠の一つに、ファイル構造を定義した「構造体」をfwriteなどの関数で書き込むというのがあります。ゴミが入って思うようには動かないコードが出来あがる。これは構造体のメンバをメモリ上で連続させない事が許されるからです(境界調整)。

さて、今の復習。doubleが8バイトの処理系の場合、以下の構造体の大きさは、全部で何バイトになるでしょうか?

struct tagFileHeader {
	char a;
	double b;
}


答えはなし。C言語では処理系定義になります。

構造体のメンバが先頭から数えて何バイト目になるかが未定義。後は、offsetof関数を調べること、以上。ではなく一応解説。

1バイト8ビットと定義します。16ビットのレジスタ(記憶域)を持つCPUで上記構造体のメンバaを読み出す場合、「16ビット専用のコンパイラさん」がどう考えるか。aとbの領域を連続して置きたくないんです。

16ビットCPUでは、16ビットを纏めて読み込む事が多いです。連続させてしまうと、上位(または下位)8ビットにaが、残り8ビットにb、またはbの一部が入ります。直接使いたいのはaである事が多いのに。そして、bを読み込むときには、少し戻って読み直さなくてはなりません。

これが処理系定義となる理由の1例で、要はコンパイラさんが勝手に決めたほうが都合が良い事が多い。

例として、16ビットCPUのコンパイラさんは16ビットずつ処理したいので、aのあとに8ビット分のダミー領域を作る事が多い。64ビットCPU用のコンパイラさんは56ビットのが良いのかもしれません。厳密には、メンバbが全部で何バイト必要かとか、そのCPUが何バイト同時に読み込めるかによるのですが。

C++を含めた話は、「POD」などの一見専門用語風が出てくるのでやめておきます。

Leave a Reply

最初のコメントを頂けますか?

更新通知を受け取る »
avatar
wpDiscuz