结构体对齐计算方式

Posted 行稳方能走远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构体对齐计算方式相关的知识,希望对你有一定的参考价值。


对齐方式确实很浪费空间,可是按照计算机的访问规则,这种对齐方式提升了效率。

法则一:结构体成员的偏移量必须是成员大小的整数倍(数组除外)

#include<stdio.h>
#include<stdlib.h>


struct s1{
    char ch1;	//1
    char ch2;	//1
    int i;		//4 2
};

int main()
{

        printf("char = %d\\n",sizeof(char));
        printf("float = %d\\n",sizeof(float));
        printf("int = %d\\n",sizeof(int));
        printf("double = %d\\n",sizeof(double));

        printf("S1 = %d\\n",sizeof(struct s1));
        return 0;


}

在这里插入图片描述

首先,第一个成员ch1 的偏移量为0(可以这么理解 距离结构体头距离为0),ch1的类型为char,大小为1字节,0被认为是任何数的整数倍,所以到ch1这里大小为1;
第二个成员ch2,ch2的偏移量是前面成员的大小和(这个大小和是遵循第一法则的前提下的大小和,不是随意加起来就行的),所以ch2的偏移量为1,1满足ch2的大小1的整数倍,所以到ch2这里大小为1+1 = 2;
最后i,int i的偏移量为1+1 = 2,但2不是int型大小4的整数倍,所以要在前面加上2(多偏移两个),将之变为4,才满足第一法则。
综上s1的大小为1+1+2+4 = 8;

法则二:结构体大小必须是所有成员大小的整数倍(数组、结构体除外)

struct s2{

	char ch1;	//1
	int i;		//4  3
	char ch2;	//1  3

};

根据第一法则可以简单计算下s2的大小:
到ch1这里为1
到int这里为1+3+4 = 8
到ch2这里 8+1 = 9;
但是运行结果为12。
因为9不是4和1的整数倍(遵循第二法则),所以要继续偏移,直到12。

带数组的结构体大小计算

struct s3{
    char ch1;
    int i;
    char str[10];
};

1+3+4+10 = 18,因为18不是4的倍数,所以要偏移到20。这里偏移到20不是因为str数组的大小为10才偏移的,是因为i的大小为4,法则一和法则二都是除数组外


当结构体里有数组的时候,数组那一成员不遵循偏移量和数组成员大小对齐法则,直接将前面的大小加上数组的大小。 举个例子:

struct demo{
    char ch1;
    int i;
    char str[32];
};

这个demo计算到int i的时候为8,8直接加上数组大小32为40,40正好是4的整数倍,所以demo的大小就为40。


再举个例子:

struct demo{
    char ch1;
    int i;
    char str[55];
};

8+55 = 63,63不是4的整数倍,所以要偏移到64,即demo的大小为64。

带结构体的结构体大小计算

struct s4{
    char ch;  		//1
    int i;   		//4 3
    struct s{		//只是定义了个结构体 不算入
        char ch1;	//
        int j;		//
    }; 
    float f;		//4
};

大小:12


struct s4{
    char ch;  		//1
    int i;   		//4  3
    struct s{		//定义 并且占用内存8
        char ch1;	//1
        int j;		//4  3
    }stmp; 
    float f;		//4
};

里面这个结构体的大小是8,那么是否结构体大小就要向8对齐呢?这个结构体的大小是20,很明显不是8的倍数。所以计算结构体大小时是把里面这个结构体就看做是一个char,和一个int,不是看做一个整体。


struct s4{
    char ch;  		//1
    int i;   		//4  3
    struct s{		//定义 并且占用内存
        char ch1;	//1
        int j;		//4  3
        double d;   //8
    }stmp; 
    float f;		//4
};

28(不是double的倍数+4)–>32

带联合体的结构体大小计算

struct s5{
    char ch;  
    int i;   
    union{
        char ch1;
        int j;
    }; 
};

结果为12,算结构体大小的时候,如果里面有联合体,取联合体里面最大的成员计算。

pragma pack(4)向4对齐

#pragma pack(4) 	//指定向4对齐  
struct s6{
    char ch;
    int i;
    float f;
    double d;
};

#pragma pack(4) 这句话是指定计算大小的时候向4对齐
结果为20,不加这句话结果就是24。

#pragma pack(10) 	//指定向10对齐  
struct s7{
    char ch;
    int i;
    float f;
    double d;
};

1+3+4+4+4+8 = 24。
这一个在ubuntu中运行结果为24,没有对齐10,是因为最大时double,如果指定的比成员最大的还要大就按照成员最大的对齐

以上是关于结构体对齐计算方式的主要内容,如果未能解决你的问题,请参考以下文章

结构体内存对齐

[.NET] 结构体布局详解与结构体内存对齐具体方式

[.NET] 结构体布局详解与结构体内存对齐具体方式

Visual Studio2008 C++结构体成员需要内存对齐吗?

结构体中的数据对齐

结构体内存的对齐方式