温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C语言中结构体与内存对齐的示例分析

发布时间:2022-03-04 14:40:15 来源:亿速云 阅读:232 作者:小新 栏目:开发技术

这篇文章主要为大家展示了“C语言中结构体与内存对齐的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言中结构体与内存对齐的示例分析”这篇文章吧。

    一、引例

    到底什么是结构体内存对齐,我们用一段代码来介绍一下

    struct S1
    {
    	char c1;//1字节
    	int a;//4字节
    	char c2;//1字节
    };
    int main()
    {
    	printf("%d\n", sizeof(struct S1));
    	//这里打印12
    }

    先来解释S1,结构体S1中有2个char类型,1个int类型。那按道理应该是占2*1+4=6个字节啊,为什么打印的是12呢?到这里,我们必须要来了解一下结构体内存对齐的规则:

    1.结构体的第一个成员永远放在结构体起始位置偏移量为0的位置

    对于偏移量你可以这样理解:数组下标为0的相对它自己偏移量为0,下标为1的相对下标为0的偏移量为1…
    举例说明:

    C语言中结构体与内存对齐的示例分析

    S1第一个成员是c1,它会被放在结构体起始位置偏移量为0的位置,如下图红色部分

    C语言中结构体与内存对齐的示例分析

    2.从第二个成员开始,总是放在偏移量为一个对齐数的整数处,对齐数=编译器默认的对齐数和变量自身大小的较小值

    对齐数=min(编译器默认的对齐数,变量自身大小)
    Linux-没有对齐数,VS下对齐数默认为8

    我们仍以S1这个结构体进行举例,结构体第二个成员是int类型的a,占4个字节,笔者VS环境下默认对齐数是8,取两者较小值是4,那a应该放到偏移量为4的倍数上

    C语言中结构体与内存对齐的示例分析

    放到4的倍数上也就说可以放在偏移量为4这里,偏移量为1,2,3的这3个空间就白白被浪费了。而a是int型占4个字节,所以会一直占用到偏移量为7的位置。

    接下来是结构体的第三个成员,char类型的c2,c2占1个字节,VS环境下默认对齐数是8,取较小值为1,也就是说只要是1的倍数的偏移量都可以放,我们紧接着放在a后面,也就是偏移量8的位置

    C语言中结构体与内存对齐的示例分析

    那到这里结构体3个成员都用完了啊,只有8个啊,为什么打印是12呢?这里就要涉及结构体内存对齐的第3个规则

    3.结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍

    我们由前面讲解知道结构体三个成员c1,a,c2对齐数分别为1,4,1这三个中最大对齐数是4,总大小要为4的整数倍,那这时候肯定有小伙伴会问:我们现在不是对齐到8了嘛,8不是4的倍数吗?注意!这里说的是空间总大小,而8是所谓的偏移量,偏移量是从0开始算的,到8已经有9个空间了,所以我们这里空间要到12,也就是偏移量到11

    C语言中结构体与内存对齐的示例分析

    (后面加上的三个空间用不到,但是由于规定还是算在结构体总空间内)

    二、小试牛刀

    我们再来看一道类似的题目

    代码如下(示例):

    struct S2
    {
    	char c1;//1字节
    	char c2;//1字节
    	int a;//4字节
    };
    int main()
    {
    	printf("%d\n", sizeof(struct S2));
    	//这里打印8
    }

    首先第一个结构体成员是char类型的c1,由规则1,它会直接被放在偏移量为0的位置
    (图示灰色部分)

    C语言中结构体与内存对齐的示例分析

    第二个成员是char类型的c2,占1字节,VS下默认对齐数是8,取较小值是1,只要放在偏移量为1的倍数上即可(任意位置),紧跟着0,放在偏移量为1处(图示红色部分)

    C语言中结构体与内存对齐的示例分析

    最后一个成员int类型的a,占4个字节,VS环境下默认对齐数是8,取较小者4,放在偏移量为4的整数倍处,也就是4这里,然后由于int占4个字节所以一直占用到偏移量7处

    C语言中结构体与内存对齐的示例分析

    再来看看规则3,结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍,也就是4的倍数,我们现在正好是占8个空间,8正好是4的倍数,所以就不用再往下浪费空间了,打印出8

    三、嵌套结构体的特殊情况

    代码如下(示例):

    struct S3
    {
    	double d;//double占8字节,默认对齐数8,取较小值,对齐数8
    	char c;//对齐数1
    	int i;//对齐数4
    };
    struct S4
    {
    	char c1;
    	struct S3 s3;
    	double d;
    };
    int main()
    {
    	printf("%d\n", sizeof(struct S4));
    }

    关于结构体S3我们可以采用和前面S1、S2一样的方法计算出来是占16个字节空间,我们这里重点讨论S4,对S3有兴趣的小伙伴可自行求解。

    S4中的第一个成员c1,按规则1直接放在偏移量为0处,第二个成员s3怎么办呢?这里涉及结构体内存对齐的第四个规则:

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

    s3这个结构体三个成员最大对齐数是8,也就是要对齐到偏移量为8的倍数处,然后s3是占16个字节,所以一直占到偏移量23处(s3结构体对齐数是本身s3结构体三个成员中最大对齐数)

    ps:在VS环境中,嵌套结构体的最大对齐数超过8,仍然用8做最大对齐数(比默认对齐数大了,取较小值就取默认对齐数了)

    C语言中结构体与内存对齐的示例分析

    S4最后一个成员double类型的d占8字节,默认对齐数8,对齐数取8,然后放在偏移量为对齐数的整数倍处,正好往下放在24处,本身占8字节所以占到31

    C语言中结构体与内存对齐的示例分析

    偏移量0-31共占32字节,S4中的成员c1,s3,d对齐数分别为1,8,8所以最大对齐数是8,32恰是8的倍数,所以这里不用再浪费空间来满足 “结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍”这个规则,结构体总大小就是32

    四、关于为什么存在内存对齐

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

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

    2.性能原因:

    数据结构(尤其是栈),应尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅仅需要1次
    总体来说:结构体的内存对齐是用空间换时间

    以上是“C语言中结构体与内存对齐的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI