结构体对齐

参考链接:https://www.cnblogs.com/sjxbg/p/5691231.html

                 https://blog.csdn.net/qq_29344757/article/details/62043834

                 https://blog.csdn.net/dai_wen/article/details/78304568

结构体的对齐原则(64位):

1.在结构体中,所有的成员的偏移量(结构体成员的地址-结构体的首地址 = 偏移量)必须是该成员大小的整数倍

2.结构体的总大小必须可以整除最宽基本成员

3.如果结构体中,内嵌了构造类型(枚举,数组,结构体,共同体),那么这个结构体是按照其成员来对齐的。

偏移量

struct my
{    
     int num1;
     char num2;          //偏移量是4,可以整除1,  
     double num3;       // 偏移量是13,要想整除8,需要在char后边填充三个字节
     char num4;         //加上这个就是17个字节了,要想让它能够整除最宽的基本成员,需要在char后边填充7个字节
};
总字节是24字节。

数组和字符串都不属于最宽基本成员。

struct Mystruct
{
      char str[13];
      double a;  
};    //该结构体占用24个字节

struct Mystructx
{
       struct Mystrct test;
       char b;  //结构体嵌套的情况下,最宽基本成员不局限于当前的结构体,会把被嵌套的结构体成员也算上。。
};  //这个结构体占用32个字节

结构体嵌套

typedef struct _m {
    int a;    //4Byte
    char b;   //1Byte
    char c;   //1Byte
    short n;  //2Byte
}m;            //共占据8Byte

typedef struct _t {
    int aa;    //4Byte
    short bb;  //2Byte
    m mm;      //8Byt
}t;          //共16Byte

结构体类型m总共占据8Byte,但在计算结构体t类型的大小时,并不会把m为整体看成一个整体的大小来计算对齐字节,而是拆开m结构体,依次拿m里的成员来存放于内存中。

 结构体的对齐原则(32位):

 32位下有一个限制,最大对齐的字节数不超过4字节
(就是补位的时候不要除以下一个存储类型大小,只能看是不是4的倍数)
 注意下面的情况,数据类型摆放的顺序不同会影响结构体的大小

struct foo{
char a;
int b;
char c;
};


foo的大小是12个字节
f=0x7ffdf596b4b0
f.a=0x7ffdf596b4b0
f.b=0x7ffdf596b4b4
f.c=0x7ffdf596b4b8
 

struct foo{
int a;
char b;
char c;
};

foo的大小8个字节
f=0x7ffc46115130
f.a=0x7ffc46115130
f.b=0x7ffc46115134
f.c=0x7ffc46115135

 

补充:

1、偏移量

struct   A
            {
               int a;
               char b;
               double c;
               char d;
            };

解析: 
windows系统32位平台上: 
int占4个字节 
char占1个字节 
float占4个字节 
double占8个字节 
int a从0偏移开始,占四个字节,即占用0,1,2,3,现在可用偏移为4偏移,接下来存char b; 由于4是1的倍数,故而,b占用4偏移,接下来可用偏移为5偏移,接下来该存double c; 由于5不是8的倍数,所以向后偏移5,6,7,都不是8的倍数,偏移到8时,8是8的倍数,故而c从8处开始存储,占用8,9,10,11,12,13,14,15偏移,现在可用偏移为16偏移,最后该存char d ;因为16是1的倍数,故d占用16偏移,接下来在整体向后偏移一位,现处于17偏移,min(默认对齐参数,类型最大字节数)=8;因为17不是8的倍数,所以继续向后偏移18…23都不是8的倍数,到24偏移处时,24为8的整数倍,故而,该结构体大小为24个字节。 
示意图
方法总结: 
a、从零偏移处开始,按字节大小计算,判断此偏移地址是否为该成员变量和对齐参数两者之间的最小值,即min(对齐参数,sizeof()成员); 
b、若是,则从此处开始占用内存,大小为该类型所占字节数值,若不是,则内存向后偏移到最小值整数倍处,再开始占用空间。 
c、按a、b、两步骤算出结构体实际所占内存时,为了方便后面类型的存储,再向后偏移一位,然后判断该地址是否是默认对齐数与该结构体中最大类型所占字节数的最小值 ,即:min(默认对齐参数,类型最大字节数)的整数倍,若是,则当前偏移地址的字节数便是结构体大小,若不是,继续向后偏移,直至为最小值整数倍为止。 

2、对齐参数如何设置?可以设置为按照任意字节数对齐吗? 


解析:在windows中,VS编译器下,默认对齐数为8; 
在Linux中,默认对齐数为4 
设置对齐参数可在结构体struct之前加上#pragma pack(对齐数),在struct之后加上#pragma pack;便可以设置对齐参数。 
for example3:

#pragma pack(4)
struct   A
            {
               int a;
               char b;
               double c;
               char d;
            };
#pragma pack;

对齐参数不能任意设置,只能是内置类型已有的字节数,如:char(1)、short(2),int(4),double(8)…不能是3,5…任意数。 

 

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