结构体的大小如何计算?

  • 看了一些博客上关于结构体计算的讲法,有些没讲全面,有些根本就是错误的,可能作者本人都没意识到自己错了,我总结一下加深印象。
  • 结构体的大小如何计算?

  • 答:由于存储变量地址对齐的问题,结构体大小计算必须满足三条原则:

         一,结构体变量的首地址,必须是结构体 "最宽基本类型成员" 大小的整数倍。

         二,结构体每个成员相对于结构体首地址的偏移量,都是该成员的整数倍。

         三,结构体的总大小,为结构体 “最宽基本类型成员” (将嵌套结构体里的基本类型也算上,得出的最宽基本类型) 大小的整数倍。

    1、简单结构体
    struct s1{
    char ch1;
    char ch2;
    int i;
    };
    

    这个结构体的大小容易计算,满足后两个原则即可,为8。

    struct s2{
    char ch1;
    int i;
    char ch2;
    };
    

    这个结构体大小是12,为什么呢?仔细看看后两个原则,要满足偏移量是成员的整数倍,ch1偏移量是0,i的偏移量不可能是1,因为1不是i大小4的倍数,所以i的偏移量是4,ch2的偏移量就变为了8,加ch2是9,要满足结构体大小是成员大小整数倍,就是12。

    2、成员包含数组的结构体
    struct s3{
    char ch;
    int i;
    char str[10];
    };
    

    这个结构体的大小是20,先看前两个成员,大小是8,毋庸置疑,这个char类型的数组,只需要把它看做十个char连在一起即可,加起来就是18,再满足结构体大小为成员整数倍,所以大小就是20。

    3、嵌套结构体的结构体
    struct s4{
        char ch;
        int i;
        struct s{
            char ch1;
            int j;
        }sub;
        float f;
    };
    

    里面这个结构体的大小是8,那么是否结构体大小就要向8对齐呢?这个结构体的大小是20,很明显不是8的倍数。所以计算结构体大小时是把里面这个结构体就看做是一个char,和一个int,不是看做一个整体。

    struct s4{
        char ch;
        char i;
        struct s{
            char ch1;
            double j;
        }sub;
        char f;
    };
    

    结果:32

    4、成员包含联合体的结构体
    struct s5{
    char ch;
    int i;
    union{
    char ch1;
    int j;
    };
    };
    

    联合体大小就是成员中最大类型的大小,所以这个结构体大小是12.

    5、指定对齐值

    (1)对齐值小于最大类型成员值

    #pragma pack(4)  //指定向4对齐 最大是8
    struct s6{
    char ch;
    int i;
    float f;
    double d;
    };
    

    如果我们没有指定对齐值,这个结构体大小是24,我们指定向4对齐,所以大小是4的倍数,所以结构体大小是20。

    (2)对齐值大于最大类型成员值

    #pragma pack(10)
    struct s7{
    char ch;
    int i;
    float f;
    double d;
    };
    

    我们指定的对齐值是10,最大为8,是否就向10对齐?不是,当指定对齐值大于自身对齐值时,向自身对其值对齐,大小是24.

    总的来说,向指定对齐值和自身对齐值中较小的那个值对齐。

    (3)指定对齐为2

    #pragma pack(2)
    struct s7{
    char ch;
    int i;
    float f;
    double d;
    };
    #pragma pack
    

    结果:
    18

    (4)

    #include "stdafx.h"
    #include 
    #pragma pack(1)
    struct s3{
    char ch;
    int i;
    struct s{
    char ch1;
    int j;
    }sub;
    float f;
    };
    #pragma pack
    
    #pragma pack(2)
    struct s4{
    char ch;
    int i;
    struct s{
    char ch1;
    int j;
    }sub;
    float f;
    };
    #pragma pack
    
    #pragma pack(4)
    struct s5{
    char ch;
    int i;
    struct s{
    char ch1;
    int j;
    }sub;
    float f;
    };
    #pragma pack
    
    #pragma pack(8)
    struct s6{
    char ch;
    int i;
    struct s{
    char ch1;
    int j;
    }sub;
    float f;
    };
    #pragma pack
    
    int main()
    {
    printf("%d\n", sizeof(struct s3));
    printf("%d\n", sizeof(struct s4));
    printf("%d\n", sizeof(struct s5));
    printf("%d\n", sizeof(struct s6));
    return 0;
    }
    

    输出结果:
    14
    16
    20
    20

    #pragma pack(n) 需要以 #pragma pack()作结束,表示该种对齐方式至此为止。

    由以上三例可见,“ 在有指定对齐方式 ” 时,本文开头的三条原则修改为(以下min表示求最小值):

    一,结构体变量的首地址,必须是 min("结构体最宽基本类型成员", 指定对齐方式) 大小的整数倍。

    二,结构体每个成员相对于结构体首地址的偏移量,都是 min(该成员, 指定对齐方式)大小的整数倍。

    三,结构体的总大小,为min( 结构体 “最宽基本类型成员” (将嵌套结构体里的基本类型也算上,得出的最宽基本类型),    指定对齐方式) 大小的整数倍。

    6、再看一道微软的笔记题
    #include "stdafx.h"
    #include 
    #pragma pack(8)
    struct S1
    {
    short a;
    long b;
    };
    
    struct S2
    {
    char c;
    struct S1 d;
    double e;
    };
    
    #pragma pack()
    int main()
    {
    struct S2 s2;
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    printf("%d\n", (int)&(s2.d) - (int)&(s2.c));
    return 0;
    }
    结果:
    8
    24
    4
    
    #include "stdafx.h"
    #include 
    #pragma pack(4)
    struct S1
    {
    short a;
    long b;
    };
    
    struct S2
    {
    char c;
    struct S1 d;
    double e;
    };
    
    #pragma pack()
    int main()
    {
    struct S2 s2;
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    printf("%d\n", (int)&(s2.d) - (int)&(s2.c));
    return 0;
    }
    结果:
    8
    20
    4
    
    #include "stdafx.h"
    #include 
    #pragma pack(2)
    struct S1
    {
    short a;
    long b;
    };
    
    struct S2
    {
    char c;
    struct S1 d;
    double e;
    };
    
    #pragma pack()
    int main()
    {
    struct S2 s2;
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    printf("%d\n", (int)&(s2.d) - (int)&(s2.c));
    return 0;
    }
    结果:
    6
    16
    2
    
    #include "stdafx.h"
    #include 
    #pragma pack(1)
    struct S1
    {
    short a;
    long b;
    };
    
    struct S2
    {
    char c;
    struct S1 d;
    double e;
    };
    
    #pragma pack()
    int main()
    {
    struct S2 s2;
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    printf("%d\n", (int)&(s2.d) - (int)&(s2.c));
    return 0;
    }
    结果:
    6
    15
    1
    

你可能感兴趣的:(开发类,c++)