Cの構造体のアライメントにハマった(1日ぶり2回目)
えぇまたです、またCです(前回記事参照)。正直、Cの話なんてググれば大量に記事が上がってくるので書く必要なんてないのだけど(そもそもCマスターな人たちはネットの記事なんて読まないし)、まぁアレです、自分用メモです。
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct T_FOOBAR { int foo; short bar; int tydk; } FOOBAR; typedef struct T_HOGEPIYO { int foo; short bar; int tydk; } HOGEPIYO; int main() { FOOBAR foobar; HOGEPIYO *hogepiyo; hogepiyo = (HOGEPIYO*)malloc(sizeof(HOGEPIYO)); memset(hogepiyo, 0x00, sizeof(HOGEPIYO)); printf("foo : %p\n", &hogepiyo->foo); printf("bar : %p\n", &hogepiyo->bar); printf("tydk : %p\n", &hogepiyo->tydk); foobar.foo = 100; foobar.bar = 1; foobar.tydk = 200; memcpy(hogepiyo, &foobar, sizeof(FOOBAR)); free(hogepiyo); return 0; }
構造体を動的確保し、各変数のポインタを表示するというもの。これをVC2013でビルドすると以下の様な感じになります。
foo : 0x004E8D50 bar : 0x004E8D54 tydk : 0x004E8D58
barはshort型ですが、コンパイラが勝手にアライメントしてくれているので、tydkはbarの4バイト先になっています。じゃあmemcpy後の、0x004E8D56と0x004E8D57の値はどうなってんの?ってことですが、VS2013でメモリを見ると、それぞれ0xccが入ってました。Visual Studioさんが勝手に入れている証拠。コンパイラすげぇですね(小並感)
アライメントきんもー、な方はbarの下にもう1個short型の変数を追加したり、#pragma pack(2)とか付ければいい。まぁしないけど。
そもそもの話、ここで問題になってくるのはポインタをインクリメントしたりして構造体内部の次の変数をゲットする時とかなわけです。えぇそうです、わたしがやりました。「あれれー、char2バイトの後ろに、どうして値がはいってないんだー?」的な。Cで飯を食っているような人からすれば「なにその単純ミス、猫でもしないよ」とお思いになられるでしょうが、でもでも、メモリとか意識しなくていい言語で遊んできた私ですので…(言い訳)