zoukankan      html  css  js  c++  java
  • 【C语言】字节对齐(内存对齐)

    1.  对齐原则:

    【原则1】数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

    【原则2】结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

    【原则3】结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

    备注:数组成员按长度按数组类型长度计算,如char t[9],在第1步中数据自身长度按1算,累加结构体时长度为9;第2步中,找最大数据长度时,如果结构体T有复杂类型成员A,该A成员的长度为该复杂类型成员A的最大成员长度。

    小结:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。


     【注意】(对齐位数跟处理器位数和编译器都有关)VS, VC等编译器默认是#pragma pack(8),所以测试我们的规则会正常;注意gcc默认是#pragma pack(4),并且gcc只支持1,2,4对齐。套用三原则里计算的对齐值是不能大于#pragma pack指定的n值。

    2. 自然对齐存放变量的地址要是该变量数据类型大小的整数倍。如:存放int型数据的地址一定要是4的倍数,存放short型数据的地址一定要是2的倍数。

    3. 改变缺省的对界条件(指定对界):

    • 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
    • 使用伪指令#pragma pack(),取消自定义字节对齐方式。

    举例一

    例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #pragma pack(1)
    struct AA
    {
        int a;   //长度4 < 1 按1对齐;偏移量为0;存放位置区间[0,3]
        char b;  //长度1 = 1 按1对齐;偏移量为4;存放位置区间[4]
        short c; //长度2 > 1 按1对齐;偏移量为5;存放位置区间[5,6]
        char d;  //长度1 = 1 按1对齐;偏移量为6;存放位置区间[7]
        //整体存放在[0~7]位置区间中,共八个字节。
    };
    #pragma pack()

     结果:8个字节

    例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #pragma pack(2)
    struct AA
    {
        int a;   //长度4 > 2 按2对齐;偏移量为0;存放位置区间[0,3]
        char b;  //长度1 < 2 按1对齐;偏移量为4;存放位置区间[4]
        short c; //长度2 = 2 按2对齐;偏移量要提升到2的倍数6;存放位置区间[6,7]
        char d;  //长度1 < 2 按1对齐;偏移量为7;存放位置区间[8];共九个字节
    };
    #pragma pack()

     结果:10个字节

    例3:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #pragma pack(4)
    struct AA
    {
        int a;   //长度4 = 4 按4对齐;偏移量为0;存放位置区间[0,3]
        char b;  //长度1 < 4 按1对齐;偏移量为4;存放位置区间[4]
        short c; //长度2 < 4 按2对齐;偏移量要提升到2的倍数6;存放位置区间[6,7]
        char d;  //长度1 < 4 按1对齐;偏移量为7;存放位置区间[8];总大小为9
    };
    #pragma pack()

     结果:12个字节

    例4:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #pragma pack(8)
    struct AA
    {
        int a;   //长度4 < 8 按4对齐;偏移量为0;存放位置区间[0,3]
        char b;  //长度1 < 8 按1对齐;偏移量为4;存放位置区间[4]
        short c; //长度2 < 8 按2对齐;偏移量要提升到2的倍数6;存放位置区间[6,7]
        char d;  //长度1 < 8 按1对齐;偏移量为7;存放位置区间[8],总大小为9
    };
    #pragma pack()

     结果:12个字节  

    例5:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    struct EE  //8个字节对齐
    {
        int a;      //长度4 < 8 按4对齐;偏移量为0;存放位置区间[0,3]
        char b;     //长度1 < 8 按1对齐;偏移量为4;存放位置区间[4]
        short c;    //长度2 < 8 按2对齐;偏移量由5提升到6;存放位置区间[6,7]
     
        struct FF   //结构体内部最大元素为int,由于偏移量为8刚好是4的整数倍,所以从8开始存放接下来的struct FF
        {
            int a1;     //长度4 < 8 按4对齐;偏移量为8;存放位置区间[8,11]
            char b1;    //长度1 < 8 按1对齐;偏移量为12;存放位置区间[12]
            short c1;   //长度2 < 8 按2对齐;偏移量为13,提升到2的倍数14;存放位置区间[14,15]
            char d1;    //长度1 < 8 按1对齐;偏移量为16;存放位置区间[16]
        };              //整体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由17补齐到4的整数倍20
         
        char d;         //长度1 < 8 按1对齐;偏移量为21;存放位置区间[21]
                        //整体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由21补齐到4的整数倍24
    };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct B
    {
        char e[2];      //长度1 < 8 按2对齐;偏移量为0;存放位置区间[0,1]
        short h;        //长度2 < 8 按2对齐;偏移量为2;存放位置区间[2,3]
                        //结构体内部最大元素为double,偏移量为4,提升到8,所以从8开始存放接下来的struct A
        struct A
        {
            int a;      //长度4 < 8 按4对齐;偏移量为8;存放位置区间[8,11]
            double b;   //长度8 = 8 按8对齐;偏移量为12,提升到16;存放位置区间16,23]
            float c;    //长度4 < 8,按4对齐;偏移量为24,存放位置区间[24,27]
        };
        //整体对齐系数 = min((max(int,double,float), 8) = 8,将内存大小由28补齐到8的整数倍32
    };

    举例二

    代码1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    #include <stdio.h>
    typedef struct
    {
        int aa1;   //4个字节对齐 1111 
        char bb1;  //1个字节对齐 1 
        short cc1; //2个字节对齐 011 
        char dd1;  //1个字节对齐 1 
    }testlength1;
    int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12
     
    typedef struct
    {
        char bb2;  //1个字节对齐 1 
        int aa2;   //4个字节对齐 01111 
        short cc2; //2个字节对齐 11 
        char dd2;  //1个字节对齐 1 
    }
    testlength2;
    int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011  1111 1000,length = 12
     
    typedef struct
    {
        char bb3;   //1个字节对齐 1 
        char dd3;   //1个字节对齐 1 
        int aa3;    //4个字节对齐 001111 
        short cc23; //2个字节对齐 11 
    }testlength3;
    int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12
     
    typedef struct
    {
        char bb4;  //1个字节对齐 1 
        char dd4;  //1个字节对齐 1 
        short cc4; //2个字节对齐 11 
        int aa4;   //4个字节对齐 1111 
    } testlength4;
    int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8
     
    int main(void)
    {
        printf("length1 = %d. ",length1);
        printf("length2 = %d. ", length2);
        printf("length3 = %d. ", length3);
        printf("length4 = %d. ", length4);
        return 0;
    } 

    VS2017输出结果:

     代码2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #include <stdio.h>
    #pragma pack(2)
     
    typedef struct
    {
        int aa1;   //2个字节对齐 1111 
        char bb1;  //1个字节对齐 1 
        short cc1; //2个字节对齐 011 
        char dd1;  //1个字节对齐 1 
    } testlength1;
    int length1 = sizeof(testlength1); //2个字节对齐,占用字节11 11 10 11 10,length = 10
     
    typedef struct
    {
        char bb2;    //1个字节对齐 1
        int aa2;     //2个字节对齐 01111 
        short cc2;   //2个字节对齐 11 
        char dd2;    //1个字节对齐 1 
    } testlength2;
    int length2 = sizeof(testlength2); //2个字节对齐,占用字节10 11 11 11 10,length = 10
     
    typedef struct
    {
        char bb3;   //1个字节对齐 1 
        char dd3;   //1个字节对齐 1 
        int aa3;    //2个字节对齐 11 11 
        short cc23; //2个字节对齐 11 
    }testlength3;
    int length3 = sizeof(testlength3); //2个字节对齐,占用字节11 11 11 11,length = 8
     
    typedef struct
    {
        char bb4;  //1个字节对齐 1 
        char dd4;  //1个字节对齐 1 
        short cc4; //2个字节对齐 11 
        int aa4;   //2个字节对齐 11 11
    }testlength4;
    int length4 = sizeof(testlength4); //2个字节对齐,占用字节11 11 11 11,length = 8
     
    int main(void)
    {
        printf("length1 = %d. ", length1);
        printf("length2 = %d. ", length2);
        printf("length3 = %d. ", length3);
        printf("length4 = %d. ", length4);
        return 0;
    }

    VS2017输出结果:

      

    代码3:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include<iostream>
    using namespace std;
     
    typedef struct bb
    {
        int id;             //[0]....[3]
        double weight;      //[8].....[15]      原则1
        float height;       //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
    }BB;
     
    typedef struct aa
    {
        char name[2];    //[0],[1]
        int  id;         //[4]...[7]          原则1
        double score;    //[8]....[15]    
        short grade;     //[16],[17]        
        BB b;            //[24]......[47]          原则2
    }AA;
     
    int main()
    {
        AA a;
        cout << sizeof(a) << " " << sizeof(BB) << endl;
        return 0;
    }

    VS2017输出结果: 48 24

    代码4:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #include<iostream>
    using namespace std;
     
    #pragma pack(2)
    typedef struct bb
    {
        int id;            
        double weight;     
        float height;      
    }BB;
     
    typedef struct aa
    {
        char name[2];   
        int  id;       
        double score;   
        short grade;         
        BB b;          
    }AA;
     
    int main()
    {
        AA a;
        cout << sizeof(a) << " " << sizeof(BB) << endl;
        return 0;
    }

    VS2017输出结果:32 16  

  • 相关阅读:
    Redis的发布订阅
    Redis的事务
    Redis的持久化下
    Redis的持久化上
    Redis数据类型之Redis有序集合Zset(sorted set
    Redis数据类型之Redis哈希(Hash)
    Redis数据类型之Redis集合(Set)
    LeetCode#53-最大子序和
    LeetCode#442-数组中的重复数据
    LeetCode#1014-最佳观光组合
  • 原文地址:https://www.cnblogs.com/bruce1992/p/13938639.html
Copyright © 2011-2022 走看看