zoukankan      html  css  js  c++  java
  • c 结构体内存对齐详解

    0x00简介

    首先要知道结构体的对齐规制

    1.第一个成员在结构体变量偏移量为0的地址处

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

    对齐数=编辑器默认的一个对齐数与该成员大小的较小值

    vs中默认的值为8

    gcc 没有默认就是累加

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

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

    0x01结构体

    如下代码

    #include <string.h>
    #include <stdio.h>
    
    struct s1
    {
        char c1;
        int a;
        char c2;
    
    };
    
    struct s2
    {
        char c1;
        char c2;
        int a;
    
    };
    
    
    int  main()
    {
    
        struct s1 s1 = { 0 };
        printf("%d", sizeof(s1));
        struct s2 s2 = { 0 };
        printf("%d", sizeof(s2));
        return 0;
    }

    s1 的偏移量大小计算就是:

    从上到下

    char c1;

    他的字节是1  就是 1/8  取最小值 第一个就是1  此时偏移量大小就是1

    int a;

    他的字节是4  就是 4/8  取最小值 就是4  偏移量大小应该是4的倍数 前面1就要填充3个 就是 4 在加int  此时偏移量大小就是8

    char c2;

    他的字节是1  就是 1/8  取最小值 第一个就是1  由于他是最后一个完了就是结构体  此时偏移量是8+1=9 但是结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍他个结构体最大对齐数是4 所以9不是4的倍数 要在填充3个  就是12个长度

    s2的偏移量大小计算就是:

    char c1;

    他的字节是1  就是 1/8  取最小值 第一个就是1  此时偏移量大小就是1

    char c2;

    他的字节是1  就是 1/8  取最小值 第一个就是1 此时偏移量大小就是2

    int a;

    他的字节是4  就是 4/8  取最小值 就是4  偏移量大小应该是4的倍数 前面是2就要填充2个 就是 4 在加int  此时偏移量大小就是8 正好是4的倍数不用在加了

    这时查看输出结果

    12
    8

    0x02结构体嵌套

    这里我们在看一个结构体嵌套的代码

    #include <string.h>
    #include <stdio.h>
    
    struct s3
    {
        double d;
        char  c;
        int i;
    
    };
    
    struct s4
    {
        char c;
        struct s3 s3;
        double d;
    
    };
    
    
    int  main()
    {
        printf("%d", sizeof(struct s4));
        return 0;
    }

    先计算s3结构体的大小

    double d;

    他的字节是8  就是 8/8  取最小值 第一个就是8  此时偏移量大小就是8

    char  c;

    他的字节是1  就是 1/8  取最小值 1  此时偏移量大小就是9

    int i;

    他的字节是4  就是 4/8  取最小值 4  前面偏移量是9 不是4的倍数要加3个 填充就是12 在加int   此时偏移量大小就是16 结构体最大对齐数是8所以要是8的倍数 正好是8的倍数不用加了

    再来计算s4的结构体大小

    char c;

    他的字节是1  就是 1/8  取最小值 1  此时偏移量大小就是1

    struct s3 s3;

    他的字节是16  结构体的最大对齐数是8 只需要前面是8的倍数就行了  前面是1 要补齐7个  就是1+7+16=24

    double d;

    他是8个字节  就是8/8 取最小值8 前面偏移量是24  为8的倍数不用填充 直接+8 就是32  此时结构体结束 最大对齐数是8  32正好是8的倍数不用在填充

    这个结构体就是32偏移量

    0x03为什么要对齐?

    1.平台原因:不是所有的硬件都可以在任意地址上读数据。

    2.性能原因:内存对齐就是拿空间换时间

    0x04 修改默认对齐数

    主要是使用#pragma这个预处理指令。 改名默认对齐数

    #pragma pack(1)
    struct s3
    {
        double d;
        char  c;
        int i;
    
    };
    #pragma pack()

    这里写1 就是和gcc一样的计算方式了 直接就是里面变量字节相加

    这里是13

    如果没用到pragma 考虑到性能 结构体变量声明应该是 字节小到大 例如:

    struct s3
    {
        char  c;
        char  c1;
        char  c2;
        int i;
        double d;
    };
    从此山高路远,纵马扬鞭。愿往后旅途,三冬暖,春不寒,天黑有灯,下雨有伞。此生尽兴,不负勇往。
  • 相关阅读:
    Java内存泄漏的排查总结
    多文本匹配 AC算法(Aho-Corasick)
    Linux下进程管理利器—supervise(监控并将死掉的程序重启)
    maven pom项目的dependencies转gradle格式
    Protocol Buffers官方文档(开发指南)
    Spring的工具类StringUtils使用
    springboot2 中Druid和ibatis(baomidou) 遇到org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.iflytek.pandaai.service.multi.mapper.TanancyMapper
    gradle 多模块Springboot项目 compile project引用其他模块的坑
    JAVA 运行springboot jar包设置classpath
    mysql8
  • 原文地址:https://www.cnblogs.com/feizianquan/p/14655077.html
Copyright © 2011-2022 走看看