【C语言】自定义类型:结构体--结构体内存对齐(用于计算结构体的大小)

          

结构体内存对齐

【C语言】自定义类型:结构体--结构体内存对齐(用于计算结构体的大小)

结构体内存对齐用于计算结构体的大小。

(1)对齐规则

1))结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。

2))其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数==编译器默认的对齐数与该成员变量类型大小的较小值。

vs编译器对齐数默认值为8.

linux中gcc没有默认对齐数,对齐数就是成员变量自身的大小。

3))结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。

4))如果结构体嵌套了结构体,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

例如://vs2022环境中

struct  s2
{
    char c1;
    char c2;
    int i;
};

0,1,2,3...分别为地址编号,同时也可以认为是偏移量。

分析;c1是结构体的第一个成员,则对齐到和结构体变量起始位置偏移量为0的地址处。而char   c2;c2占一个字节,vs2022默认对齐数为8,1和8最小值为1,所以c2对齐到1的整数倍的地址处,即对齐到地址为1的地址处。int i ;i占4个字节,vs2022默认对齐数为8,4和8的最小值为4,所以i对齐到4的整数倍的地址处,即对齐到地址为4的地址处,则由此可得出struct s2的最小大小是8,而结构体的总大小是最大对齐数的整数倍,对于struct  s2而言,最大对齐数为4,8是4的整数倍,所以struct   s2的总大小是8.

(2)为什么存在内存对齐?

1))平台原因(移植原因)

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2))性能原因

数据结构(尤其是栈)应该尽可能地在自然界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅需要一次访问。假设一个处理器是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则我们可能需要指向两次内存访问,因为对象可能被分放在两个8字节的内存块中。

总的来说:结构体的内存对齐是拿空间来换取时间的做法。

例如:

struct   s

{
char c;

int i ;

};

未对齐的情况:

对齐的情况:

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:让占用空间小的成员尽量集中在一起。

struct s1
{
    char ch1;
    char  c2;
    int i;

};

struct s2
{
    char  ch1;
    int i;
    char ch2;


};

s1和s2中的成员是一模一样,但s1和s2所占空间的大小有一些区别。

(3)修改默认对齐数

#pragma这个预处理指令,可以改变编译器的默认对齐数。

例如:

#define _CRT_SECURE_NO_WARNINGS
#include
#pragma pack(1)//设置默认对齐数为1;
struct s
{
    char c1;
    int i;
    char c2;
};
#pragma pack()//取消设置的对齐数,还原为默认,对齐数默认为8

结构体在对齐方式上不合适的时候,我们可以自己更爱默认对齐数。一般设置默认对齐数的时候,通常设置为2^n(2的n次方)(n>=0)

注意:Linux系统下不需要修改默认对齐数,因为Linux系统下没有默认对齐数。

版权声明:如无特殊标注,文章均来自网络,本站编辑整理,转载时请以链接形式注明文章出处,请自行分辨。

本文链接:https://www.shbk5.com/dnsj/75392.html