C-结构体对齐

技术群的筒子们有时候会提到结构体对齐,说实话这个问题还不是几句话能讲清楚的。这个问题网上一搜一大把,已经有无数的前辈总结过。看了很多网上的资料,根据我个人的一些理解,再总结一下,配了些图片,希望大家能看懂。

 

首先是结构体对齐规则:

1、对于n个字节的元素,它的首地址要能被n整除

         eg:int—4个字节的元素,它为结构体的第一个元素时,起始地址应能被4整除

                  double—8个字节的元素,它为结构体的第一个元素时,起始地址应能被8整除

2、结构体成员在内存中顺序存放,所占内存地址依次增高,第一个成员处在低地址处,最后一个成员处在高地址处,但结构体成员之间的内存分配不一定是连续的

3、对待每个成员,类似于对待单个n字节元素一样,依次为每个元素找一个合适的首地址,使其符合第一条对齐原则

4、编译器可设置对齐参数X,但这个X并不是结构体成员的实际对齐参数,结构体中每个成员的对齐参数N这样计算

         N= min(sizeof(成员类型),X)

5、整个结构体的长度必须是各成员所使用的对齐参数N中最大的那个值的整数倍

         即总长度LEN= {max(N1,N2,……,N)}的最小整数倍

6、当结构体成为为数组时,将数组的每个元素当一个成员来看待

7、当结构体成为类结构类型时,那么该过程是个递归过程,且把该成员当成一个整体来看待


上面的规则有点晕,对照着看下面的例子

#pragma pack(8)   //设置编译器以8字节对齐
struct A
{
char c; //①成员的对齐参数N1=  min(sizeof(char) , 8)     = 1
double d; //②成员的对齐参数N2 = min(sizeof(double) , 8) = 8
short s; //③成员的对齐参数N3 = min(sizeof(short) , 8)    = 2
int i; //④成员的对齐参数N4 = min(sizeof(int) , 8)      = 4
}
结构体的总成都LEN = {max(N1,N2,N3,N4)}的整数倍 ,所以长度LEN必须是8的整数倍,从下面的内存分布图中可看出,总长度是24字节

C-结构体对齐_第1张图片


#pragma pack(4)  //设置编译器以4字节对齐
struct A
{
char c; //①成员的对齐参数N1=  min(sizeof(char) , 4)     = 1
double d; //②成员的对齐参数N2 = min(sizeof(double) , 4) = 4
short s; //③成员的对齐参数N3 = min(sizeof(short) , 4)    = 2
int i; /④成员的对齐参数N4 = min(sizeof(int) , 4)       = 4
}
结构体的总成都LEN = {max(N1,N2,N3,N4)}的整数倍 ,所以长度LEN必须是4的整数倍,从下面的内存分布图中可看出,总长度是20字节

C-结构体对齐_第2张图片


#pragma pack(2)  //设置编译器以2字节对齐
struct A
{
char c; //①成员的对齐参数N1=  min(sizeof(char) , 2)     = 1
double d; //②成员的对齐参数N2 = min(sizeof(double) , 2) = 2
short s; //③成员的对齐参数N3 = min(sizeof(short) , 2)    = 2
int i; //④成员的对齐参数N4 = min(sizeof(int) , 2)       = 2
}
结构体的总成都LEN = {max(N1,N2,N3,N4)}的整数倍 ,所以长度LEN必须是2的整数倍,从下面的内存分布图中可看出,总长度是16字节

C-结构体对齐_第3张图片

#pragma pack(1)  //设置编译器以1字节对齐
struct A
{
char c; //①成员的对齐参数N1=  min(sizeof(char) , 1)     = 1
double d; //②成员的对齐参数N2 = min(sizeof(double) , 1) = 1
short s; //③成员的对齐参数N3 = min(sizeof(short) , 1)    = 1
int i; //④成员的对齐参数N4 = min(sizeof(int) , 1)        = 1
}

这个就不多说了,结构体总长15字节
C-结构体对齐_第4张图片


以上的例子都是在32位的系统上试的,这里两个结构体成员之间的“空隙”我用“cc”来填充,这纯粹是画起来方便,VS2010中这些“空隙”里的值都是0。

当然我之前在单步执行别的C程序的时候发现,很多初始化的内存、栈空间,都以"cc"字符来填充。最近在一本书上看到了解释,抄录在此:

对于X86处理器来说,0xcc是不错的填充数值,因为它是断点中断(int 03h)的机器码,如果你在调试器中运行程序并试图执行一段数据而不是执行代码时,就会陷入断点。

另外,使用0xcc的另一个好处是它可以很容易从内存转储的信息中识别出来


你可能感兴趣的:(C语言)