详解---结构体内存对齐

本文详细解释了结构体内存对齐的规则,包括基本对齐原则、嵌套结构体的对齐方式以及如何通过预处理指令修改默认对齐数。通过实例说明了内存对齐对结构体大小计算的影响。
摘要由CSDN通过智能技术生成

引言

通过以前对学习,我们都知道每个不同类型的变量在内存中都会占用不同大小的字节。
char(1字节)
short(2字节)
int(4字节)
long(8字节)
指针(通常4或8字节,取决于编译时是x86环境还是x64环境,x64是4字节)
float通常和int一样(4字节)
double通常是8字节

而结构体由多个成员组成,每个成员可以是不同的数据类型,比如整数、浮点数、字符、数组、指针等。通过结构体,可以将这些相关联的数据封装在一起。

struct 结构体名 {
    数据类型 成员1;
    数据类型 成员2;
    // 更多成员...
};

那么结构体所占用的内存大小是否是简单的成员变量的大小相加呢?
我们看看这两个结构体代码的计算:
在这里插入图片描述

两个结构体虽然成员变量相等,但结果不是简单字节的相加,且由于顺序不相等结果也不相等。
那为什么会这样呢?这就是有关结构体内存对齐的知识点了。容我慢慢道来。

结构体内存对齐规则

1.结构体的第⼀个成员要对⻬到起始位置偏移量为0的地址处
2.其他成员变量要对⻬到地址为对⻬数的整数倍的地址处。
对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量字节⼤⼩相比较的较⼩值。
我们常用的VS 中默认对齐数为 8
Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,取所有对⻬数中最⼤的数,就是最大对齐数)的整数倍。
4. 如果嵌套了结构体,被嵌套的结构体对⻬到结构体⾃⼰的成员中最⼤对⻬数的整数倍处就行,**结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)**的整数倍。

没有嵌套的结构体内存对齐

这里我们还是以代码举例:

example 1

struct Example_1 {
             //自身大小    默认对齐数    对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
    char a;    // 1字节       8              1
    int b;     // 4字节       8              4
    char c;    // 1字节       8              1
}one;

在这里插入图片描述

example 2

struct Example_2 {
    //自身大小    默认对齐数    对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
    int a;     // 4字节       8              4
    char b;    // 1字节       8              1
    char c;    // 1字节       8              1
}two;

在这里插入图片描述

相信大家通过以上过程和思路,都能做到举一反三的吧,嘻嘻,那我就结束了。

有嵌套的结构体内存对齐

struct Example_1 {
               //自身大小    默认对齐数    对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
    char a;    // 1字节       8              1
    int b;     // 4字节       8              4
    char c;    // 1字节       8              1
}one;//最大对齐数为4
struct Example_2 {
               //自身大小    默认对齐数    对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
    int a;     // 4字节       8              4
    
    struct Example_1 one;//嵌套的结构体对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处就行,那么对齐数就是4.
    
    char c;    // 1字节       8              1
}two;

int main()
{
    printf("%d\n", sizeof(one));
    printf("%d\n", sizeof(two));
     return 0;
}

这里的struct Example_2 two结构体中嵌套了结构体struct Example_1 one,那么我们看看结果会是啥呢
在这里插入图片描述
看我慢慢给你分析:
通过上面(example 1)中的代码我们已经知道结构体struct Example_1 one的大小为12。
在这里插入图片描述
这就是嵌套了结构体的结构体大小的求法。

修改默认对齐数

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

Linux中 gcc 由于没有默认对齐数,所以无法修改。

struct Example_1 {
               //自身大小    默认对齐数    对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
    char a;    // 1字节       8              1
    int b;     // 4字节       8              4
    char c;    // 1字节       8              1
}one;
#pragma pack(1)//设置默认对⻬数为1
struct S
{
                  //自身大小    默认对齐数    对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
    char c1;      //    1             1            1
    int i;        //    4             1            1
    char c2;      //    1             1            1
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
    printf("%d\n", sizeof(one));
    //猜猜结果是多少
    printf("%d\n", sizeof(struct S));
    return 0;
}

在这里插入图片描述

根据我们以上的思路,可以简单的推断出这个过程。
由于对齐数都为1,因为任何数都是1的整数倍,那么所有类型都是自上而下逐个排序,那么结果就是简单的所有类型字节大小相加了。

  • 21
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明fei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值