私の質問を明確にするために、サンプルプログラムから始めましょう:
#include <stdio.h>
#pragma pack(push,1)
struct cc {
unsigned int a : 3;
unsigned int b : 16;
unsigned int c : 1;
unsigned int d : 1;
unsigned int e : 1;
unsigned int f : 1;
unsigned int g : 1;
unsigned int h : 1;
unsigned int i : 6;
unsigned int j : 6;
unsigned int k : 4;
unsigned int l : 15;
};
#pragma pack(pop)
struct cc c;
int main(int argc, char **argv)
{ printf("%d\n",sizeof(c));
}
出力は「8」です。これは、パックしたい 56 ビット (7 バイト) が 8 バイトにパックされていることを意味し、1 バイトを無駄にしているように見えます。コンパイラがこれらのビットをどのようにメモリに配置していたのか知りたくて、特定の値を に書き込んでみました&c
。
int main(int argc, char **argv)
{
unsigned long long int* pint = &c;
*pint = 0xFFFFFFFF;
printf("c.a = %d", c.a);
...
printf("c.l = %d", c.l);
}
予想どおり、Visual Studio 2010 を使用する x86_64 では、次のことが起こります。
*pint = 0x00000000 000000FF :
c[0].a = 7
c[0].b = 1
c[0].c = 1
c[0].d = 1
c[0].e = 1
c[0].f = 1
c[0].g = 0
c[0].h = 0
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0
*pint = 0x00000000 0000FF00 :
c[0].a = 0
c[0].b = 0
c[0].c = 0
c[0].d = 0
c[0].e = 0
c[0].f = 0
c[0].g = 1
c[0].h = 127
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0
*pint = 0x00000000 00FF0000 :
c[0].a = 0
c[0].b = 0
c[0].c = 0
c[0].d = 0
c[0].e = 0
c[0].f = 0
c[0].g = 0
c[0].h = 32640
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0
等
移植性についてはしばらく忘れて、1 つの CPU、1 つのコンパイラ、および 1 つのランタイム環境に関心があると仮定してください。VC++ がこの構造を 7 バイトにパックできないのはなぜですか? それは言葉の長さですか?MSDNのドキュメントに#pragma pack
は、「メンバーの配置は、n の倍数 [私の場合は 1] またはメンバーのサイズの倍数のいずれか小さい方の境界上にある」と記載されています。7 ではなく 8 のサイズを取得する理由を誰か教えてもらえますか?