如下两个结构体 A B ,他们的实例的大小相同吗?
1 2 3 4 5 6 7 8 9 10 11 |
struct A{ char c_1; int i; char c2; }; struct B{ char c_1; char c_2; int i; }; |
两个 char
共占两个字节, 一个 int
占4个字节, 所以两个结构体都是 6个字节。但事实并非如此,在大部分计算机中,他们都不会只占 6 个字节。这涉及到 内存对齐
需知,计算机访问内存的方式,并不是一个字节一个字节访问的,而是以字长(word size)
为单位来进行访问的。32位计算机的字长为 4 字节, 64位计算机的字节为 8 字节。而所谓内存对齐, 就是将变量调整至字长的倍数的位置存放,以方便计算机访问
。
上面两个结构体在内存中的布局最有可能是这个样子的:(这里说 最有可能 是因为具体的布局要视计算机而定)
我们使用一段代码来验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
void showmem(unsigned char* p, uint32_t sz){ int len = sizeof(int*); cout<<"\t"; for(int i = 0; i<len; i++){ cout<<i<<"\t"; } cout<<endl; for(int i = 0; i<=len; i++){ cout<<"-------|"; } cout<<endl; unsigned char* t = p; uint32_t i = 0; char msg[8]; while(i < sz){ sprintf(msg, "%02d", i); cout<<msg<<"|\t"; for(int j = 0; j< len && (i+j)<sz; j++){ sprintf(msg, "%04d", *(uint8_t*)(t+j)); cout<<msg<<"\t"; } cout<<endl; i += len; t += len; } } //// //... A a{'a', 2, 'b'}; B b{'a', 'b', 2}; cout<<"A:"<<endl; showmem((unsigned char*)&a, sizeof(a)); cout<<endl; cout<<"B:"<<endl; showmem((unsigned char*)&b, sizeof(b)); cout<<endl; |
结果如下:
1 2 3 4 5 6 7 8 9 10 |
A: 0 1 2 3 4 5 6 7 -------|-------|-------|-------|-------|-------|-------|-------|-------| 00| 0097 0000 0000 0000 0002 0000 0000 0000 08| 0098 0000 0000 0000 B: 0 1 2 3 4 5 6 7 -------|-------|-------|-------|-------|-------|-------|-------|-------| 00| 0097 0098 0000 0000 0002 0000 0000 0000 |
在 A
中,c_1 i
共占一个字,c_2
占一个字。这种将多个变量放入一个字中的动作,叫作 packing
。 而组成一个字时,补充不足的部分,叫 padding
。
如何知道某种类型的变量要对齐到哪个位置呢?它取决于一个类型的 alignment
如 int 类型的alignment 为4, 那么int 类型变量的地址必定为 4 的倍数。