C语言中结构体的内存对齐问题

关于C语言中结构体的内存对齐,要搞清楚四个问题:

1、什么是结构体内存对齐?
2、为什么要内存对齐?
3、如何对齐?
4、如何避免内存对齐的影响?

首先来看第一个问题:什么是结构体内存对齐?

先来看一段代码:

#include <stdio.h>
#include <stddef.h>
struct S
{
    int i;
    char c;
    double d;
};

int main()
{
    struct S s;
    //printf("%d\n", offsetof(struct S, i));
    printf("%d\n", sizeof(s));
    return 0;
}

在windows环境下这段代码的输出结果是多少呢?如果你的答案是13,那么恭喜你成功的掉到了坑里,正确的答案是16!为什么会是16呢?请看下图解析:

这里写图片描述

如上图所示,结构体在内存中的存储方式跟我们想象中的不大一样,而是要遵守一定的原则,这种原则就是内存对齐,具体的原则内容会在下文提到。显而易见的的是结构体这样在内存中存储会浪费一定的空间(如图中黄色区域就是浪费掉的空间),既然浪费了空间,那为什么还要内存对齐?

接着来说第二个问题:为什么要内存对齐?

为什么要内存对齐呢?原因有两个:
1、使用平台的原因:不是在所有平台上都可以访问任意内存的地址,所以需要适当的进行偏移,偏移到我们可以访问的位置上进行数据存储。
2、内存对齐可以使访问速度提高:为了访问未对齐的内存,处理器需要两次内存访问;然而,对齐的内存访问仅需要一次访问。

怎么样来理解第二个原因呢?请看下图:
这里写图片描述

第二个问题理解清楚之后再来看第三个问题:如何对齐?

在此将阐述内存对齐的三个规则:
1、数据成员对齐规则:结构体中的第一个数据成员放在0偏移处,从第二个成员开始,每个数据成员存储的起始位置要从对齐数(该成员自身的大小和默认对齐数的较小值)的整数倍开始;
2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
3、收尾工作:结构体的总大小,必须是其内部最大成员的整数倍,不足的要补齐。
了解清楚规则之后再看第一个问题中所举的例子就比较容易啦

最后我们来看最后一个问题:如何避免内存对齐的影响?

方法1、尽量将结构体中相同类型的数据集中到一起,这样做可以有效的节省空间。
例1:

struct test1
{
    char c1;
    short s;
    char c2;
    int i;
};

很容易得出该结构体的大小为12;
例2:

struct test2
{
    char c1;
    char c2;
    short s;
    int i;
};

很容易得出该结构体的大小为8;
可见将相同类型的结构体成员集中到一起可以有效的节省空间。
方法2、使用#pragma pack()来修改编译器的默认对齐数
使用指令#pragma pack(n)将编译器的默认对齐数改为n
使用指令#pragma pack()编译器将取消自定义字节对齐方式
vc/vs环境下的默认对齐数为–8
Liunx环境下的默认对齐数为–8

看如下例子:(在vs环境下)

#pragma pack(1)
struct test1
{
    charchar c2;
    int i;
};
#pragma pack()

ragma pack()
“`;;
很容易得出该结构体的大小为8而不是12

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值