我们经常看到求 sizeof(A) 的值的问题,其中A是一个结构体,类,或者联合体。
为了优化CPU访问和优化内存,减少内存碎片,编译器对内存对齐制定了一些规则。但是,不同的编译器可能有不同的实现,本文只针对VC++编译器,这里使用的IDE是VS2012。
#pragma pack()是一个预处理,表示内存对齐。布局控制#pragma,为编译程序提供非常规的控制流信息。
/**********结构体的大小的规则*************/
结构体大小是处理器位数和结构体内最长数据元素所占字节数二者中较小的那一个的整数倍。
比如说,假设处理器位数为n,结构体内最大数据元素所占字节数为m。
处理器为32位,n = 4;结构体内最大数据类型为short,m = 2; n > m;结构体大小为m的整数倍,反之亦然。
注意:有些虽然是64位的操作系统,但是编译器却是32位的,此时位数为32.
class A{
int a;
char b;
short c;
};
sizeof(A)为8,为4的整数倍。
struct B{
short a;
short b;
short c;
};
sizeof(B)为6,为2(sizeof(short))的整数倍。
注意:C++中的结构体与类只有一个区别,就是结构体成员默认是public,而类默认是private。
class X{
public:
double a;
float b;
int c;
char d;
};
sizeof(X)为20,为4(处理器位数)的整数倍。
/********* #pragma pack(n) *************/
#pragma pack(n)中的n默认是4,即处理器位数32,但我们可以自己定义它的大小。
#pragma pack(1)
class A{
public:
int a;
char b;
short c;
};
此时sizeof(A)为7,为1(#pragma pack(1))的整数倍。
#pragma pack(1)
class X{
public:
double a;
int b;
short c;
char d;
};
sizeof(X)为15,为1(#pragma pack(1))的整数倍。
#pragma pack(4)
class X{
public:
double a;
int b;
short c;
char d;
};
sizeof(X)为16,为4(#pragma pack(4))的整数倍。
#pragma pack(8)
class X{
public:
double a;
int b;
short c;
char d;
};
sizeof(X)为16,为8(#pragma pack(8) 或者 sizeof(double))的整数倍。
/***************内存对齐**************/
结构体中数据元素所在内存地址由两个因素决定。
一是#pragma pack(n) 中的n,二是元素类型所占字节数,sizeof(type),两者中取较小的一个,元素内存地址到结构体或类的起始地址的偏移量为较小数的整数倍。
比如#pragma pack(n)默认为4,有以下结构体
struct A{
int a;
char b;
short c;
};
a的起始地址距离结构体起始地址的偏移量为0,是sizeof(int)的整数倍。
b的起始地址距离结构体起始地址的偏移量为4,是sizeof(char)的整数倍。
c的起始地址距离结构体起始地址的偏移量为5,不是sizeof(short)的整数倍,所以它的起始地址偏移量将会是6,而不是5。
输出a, b, c 的地址为
0043FD68
0043FD6C
0043FD6E
可以看到c的起始地址比b的起始地址大了2个字节,b占了2个字节的大小,这是因为c的类型是short型,大小为2,而n默认是4,sizeof(short) < n,所以偏移量应该是2的整数倍,这里是6.