结构体大小的计算以及内存对其原则和修改默认对齐数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构体大小的计算以及内存对其原则和修改默认对齐数相关的知识,希望对你有一定的参考价值。

1.结构体大小的计算
          **我们都知道,不论是数组还是指针都可以计算其大小,
             而同样结构体也是可以计算大小的,
             接下来我们就深入讨论如何计算结构体的大小。**

#include<stdio.h>
#includ<stdlib.h>
struct s1

    char c1;
    int a;
    char c2;

;

int main()

    printf("%d\n", sizeof(struct s1));
    system("pause");
    return 0;

大家猜猜这个求出来的结果多大呢,

话不多说,直接上结果图;
技术图片

是不是很疑惑呢,下面我就讲一讲结构体的大小怎么计算。
在这之前,我们先了解一个概念

2.结构体的内存对齐

首先内存对齐有以下几条规则

1.第一个成员在与结构体变量偏移量为0的地址处 (其实说白了就是和第一个成员变量的地址一样,就是从第一个成员变量的地址开始计算);
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处;
对齐数=min编译器默认的一个数,该成员的大小;
一般呢,vs中默认值=8,linux中默认值=4;
3.结构体总大小就为最大对齐数的整数倍,
!!每一个成员变量都有一个对齐数!!
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有对齐数(含嵌套结构体的对齐数)的整数倍。

下面我就分析一些具体的实例来帮大家理解;

#include<stdio.h>
#includ<stdlib.h>
struct s1

    char c1;     //min1,8=1
    int a;          //min4,8=4
    char c2;     //min1,8=1

;

int main()

    printf("%d\n", sizeof(struct s1));
    system("pause");
    return 0;

在刚刚这个例子中 他们的对齐数分别是1,4,1
首先在内存中找一个位置放入第一个成员变量,也就是c1;=>对应规则1
然后下一个成员变量的对齐数为4,所以存放这个成员变量的时候他的首地址应该放在4的整数倍处;=>对应规则2
然后最后一个是c2,他的对齐数是1,就紧接着放,可能有的同学觉得到这就结束了,但其实并不是,c2放完了以后,后边的三个字节也需要算上,而这么做的原因就要追溯到
=>规则3
所以最后就是12个字节的大小啦。
详情图解如下:
技术图片

看了上面的例子我想着大家可能已经了解如何计算结构体的大小,
那么大家看一看下面的这个例子,

#include<stdio.h>
#includ<stdlib.h>
struct s2

    char q1;
    char q2;
    int i;

;

int main()

    printf("%d\n", sizeof(struct s2));
    system("pause");
    return 0;

技术图片

不知道大家有没有发现这个例子和第一个例子是其实结构体成员都是一样的,只是顺序不一样,我还是用图来给大家讲解一下。
技术图片

这里先放q1,占用一个字节,然后q2的对齐数也是1,则紧接着放,占用一个字节,i的对齐数为4,则i的首地址要放在4的倍数处,则从偏移量为4处开始放起,放完后一共8个字节,同样也是最大对齐数(4)的倍数,就是这个结构体的大小。

通过这两个例子,我们就需要想一想,在设计结构体时,怎样才能满足既要内存对齐,又要节省空间呢,那就是 !!尽可能让占用空间小的成员集中在一起。

看完这两个例子,我想大家都已经理解并且学会结构体大小的计算了吧,那么下面我们算一个结构体嵌套的大小。

#include<stdio.h>
#includ<stdlib.h>
struct  s3

    double a;
    char b;
    int c;
;

struct s4

    char d;
    struct s3 e;
    double f;
;

int main()

    printf("%d\n", sizeof(struct s3));
    printf("%d\n", sizeof(struct s4));
    system("pause");
    return 0;

技术图片

大家会不会算呢,
在有结构体嵌套问题的时候,记得嵌套的结构体对齐到自己的最大对齐数的整数倍处哦,而结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

那到这可能有的人要好奇为什么要存在内存对齐呢,其原因有两点:
1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅需要一次访问。

其实说白了就是用空间来换取时间是的做法

3.修改默认对齐数

最后我们再讲一个知识点,就是修改默认的对齐数;用的是#pragma这个预处理指令;

#include<stdio.h>
#includ<stdlib.h>
#pragma pack(1)  //设置默认对齐数为6
struct s5

    char a1;
    int i1;
    char a2;

;
#pragma pack()//取消设置的默认对齐数,还原为vs自己默认的对齐数值
int main()

    printf("%d\n", sizeof(struct s5));
    system("pause");
    return 0;

技术图片

这个计算方法和上面的一模一样,就是默认对齐数改变了而已。

以上是关于结构体大小的计算以及内存对其原则和修改默认对齐数的主要内容,如果未能解决你的问题,请参考以下文章

详解结构体内存对齐

详解结构体内存对齐

结构体内存对齐

彻底搞清计算结构体大小和数据对齐原则

c语言篇 +自定义类型(枚举联合结构体)以及位段

内存字节对齐