C++字节自然对齐
示例
#include <stdio.h>
class a{
};
class b{
char b;
};
class c{
char a;
char b;
char c;
char d;
char e;
};
class d{
short a;
char b;
};
class e{
int a;
short b;
char c;
};
class f{
static int a;
char b;
};
class g{
char a;
char b;
char c;
short d;
char e;
};
class h{
class g g1;
char a;
};
class i{
class g g1;
int a;
};
int main(int argv, char** argc){
printf("class a size : %d\n", sizeof(a));
printf("class b size : %d\n", sizeof(b));
printf("class c size : %d\n", sizeof(c));
printf("class d size : %d\n", sizeof(d));
printf("class e size : %d\n", sizeof(e));
printf("class f size : %d\n", sizeof(f));
printf("class g size : %d\n", sizeof(g));
printf("class h size : %d\n", sizeof(h));
printf("class i size : %d\n", sizeof(i));
}
在G++编译器如下:
class a size : 1
class b size : 1
class c size : 5
class d size : 4
class e size : 8
class f size : 1
class g size : 8
class h size : 10
class i size : 12
结论
1. 如Class a,C++的struct或者class为空,那么字节是1,编译器自动添加了一个字节,为了保证该类型的两个对象在内存上地址是不一样的,这个和C是不一样的,C的空struct是0;
2. 对齐大小为其中类型大小最大的类型为准,但是不会超过4字节(在32位机,以int为准),所以,Class b和c的最大类型是char,所以他们的对齐大小是1(char是1);Class d最大类型是short(是2),所以对齐大小是2;Class e最大类型是int(4),所以对齐大小是4,但是为什么不是12(int、short、char各占4)呢,因为局部对齐方式又会以1或者2为对齐大小(取1或2主要看其中是否存在2的类型,否则取1、结构体的每一个成员起始地址必须是自身类型大小的整数倍),但是总长度为4的倍数;
3. 对齐大小不超过4(32位机),所以如
class d{
long long a;
char b;
};
字节大小是12,而不是16,但是VC上结果是16;
4. static成员不属于对象,所以Class f的大小不包括static int a;
5. 如果存在嵌套关系,对齐大小以基本类型为准,如Class g、h、i,所以h以2(short)为对齐方式,i以4(int)为对齐方式,但是被嵌套类g在嵌套类中的内存是独立的,所以h的大小是10(|char|char|char|padding|short|char|padding|char|padding|)而不是8(|char|char|char|padding|short|char|char|);
C++字节强制对齐
还可以强制设置对齐大小
如
#pragma pack (size) //size可以取1/2/4/8等2的指数
struct c
{
char b;
int a;
short c;
};
#pragma pack ()
struct c大小分别为7、8、12、12
紧缩方式
紧缩方式其实就是按1字节对齐,和#pragma pack (1) 效果一样。
为了防止不同编译器对齐不一样,建议在代码里面指定对齐参数。
可能重要的一点是关于紧缩结构的。紧缩结构的用途 其实最常用的结构对齐选项就是:默认对齐和紧缩。在两个程序,或者两个平台之间传递数据时,我们通常会将数据结构设置为紧缩的。这样不仅可以减小通信量,还可以避免对齐带来的麻烦。假设甲乙双方进行跨平台通信,甲方使用了“/Zp2”这么奇怪的对齐选项,而乙方的编译器不支持这种对齐方式,那么乙方就可以理解什么叫欲哭无泪了。 当我们需要一个字节一个字节访问结构数据时,我们通常都会希望结构是紧缩的,这样就不必考虑哪个字节是填充字节了。我们把数据保存到非易失设备时,通常也会采用紧缩结构,既减小存储量,也方便其它程序读出。各编译器都支持结构的紧缩,即连续排列结构的各成员变量,各成员变量之间没有任何填充字节。这时,结构的大小等于各成员变量大小的和。紧缩结构的变量可以放在1n边界,即任意地址边界。
如G++代码
class __attribute__ ((packed)) c
{
char b;
int a;
short c;
};
class c的大小为7,即按1字节对齐。
位域
它可以指定每个成员占据的bit数,由于移植性不好(每个编译器处理都不太一样),所以能不使用就不要使用,在这也不做具体分析了。