结构体的大小如何计算?

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

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

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

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

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

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 <stdio.h>

#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341

推荐阅读更多精彩内容