C++ アライメント 書いて覚えるための初心者自己中記事
構造体やクラスのメンバ変数のサイズを合計してみても
実際のサイズのほうが大きかったりする。
きっちり詰まっていまいという話。
struct parson { char name[21]; int age; char birthmonth; char sex; }; int main() { cout << sizeof(parson) << endl; system("pause"); }
こんな構造体があった場合。
私の環境では32バイトでした。
テキストも32バイトだと言っています。
char name[21]; 21バイト
int age; 4バイト
char birthmonth;1バイト
char sex; 1バイト
合計27バイトなので
5バイト多いですね。
この多いバイト分をパディング(padding) と言います。
(CSSで良く使いますね。)
今回は name と sex の後ろにそれぞれ3バイトと2バイト入っているそうです。
なぜなのか。
たいていのCPUは4バイト(32ビット) 単位でメモリにアクセスする。
さらにそこから4区分、1バイトずつの単位でアクセス。
これは32ビット機の場合だそうで、
64ビット機だと8バイト単位になるそうですが。
この4バイト単位をまたいだデータの場合はメモリに2回アクセスするということなのだそうです。
4バイト単位の境界をまたがないとに比べてアクセスの速さに差が生まれます。
これを避けるためには、なるべくまたがないようにメモリにデータを置きたいところですね。
実際今回の構造体もそれをやっていました。5バイト多かったわけですから。
これをバイトの境界をそろえる、アライン(align)するということで、
アライメント(alignment)
と言われます。
char name[21]; 21バイト
3バイトのパディング
-----------------4バイト境界
int age; 4バイト
-----------------4バイト境界
char birthmonth;1バイト
char sex; 1バイト
2バイトのパディング
-----------------4バイト境界
こんな感じです。
最後の2バイトのパディングは、同構造体の次の要素でまたがないように終わりもきっちりさせる為ですね。
先頭から何バイトなのか知る方法
offsetofマクロを使う。
struct parson { char name[21]; int age; char birthmonth; char sex; }; int main() { cout << offsetof(parson, name) << endl; cout << offsetof(parson, age) << endl; cout << offsetof(parson, birthmonth) << endl; cout << offsetof(parson, sex) << endl; cout << sizeof(parson) << endl; system("pause"); }
//output
0
24
28
29
32
確認できました。
このアライメントを変更する方法
コンパイラの設定を変える
もう一つはソースコード内で変える
ソースコードで変えるには
#pragma という前処理指令を使うらしい。
#pragma pack(1) struct parson { char name[21]; int age; char birthmonth; char sex; }; #pragma pack int main() { cout << offsetof(parson, name) << endl; cout << offsetof(parson, age) << endl; cout << offsetof(parson, birthmonth) << endl; cout << offsetof(parson, sex) << endl; cout << sizeof(parson) << endl; system("pause"); }
//output
0
21
25
26
27
#pragma pack( )
引数に入れた数値が境界の最大値になる。
1,2,4,8,16
が指定できる。
今回は境界の最大値が1となるようにしているので、すなわち境界が無いようなものですね。
ここまで