精华内容
下载资源
问答
  • 结构体内存对齐规则

    2019-07-31 15:21:39
    一个结构体变量定义完之后,其在内存中的存储并不等于其所包含元素的大小之和。 #include <iostream> using namespace std; struct A { char a; int b; double c; }; struct B { char a; double c; int ...

    一个结构体变量定义完之后,其在内存中的存储并不等于其所包含元素的大小之和。

    #include <iostream>
    using namespace std;
    struct A
    {
       char a;
       int b;
       double c;
    };
    struct B
    {
       char a;
       double c;
       int b;
    };
    int main()
    {
       cout << sizeof(A) << endl;
       cout << sizeof(B) << endl;
    
       return 0;
    }
    

    运行后其结果如下:
    在这里插入图片描述
    明明是相同的结构体,可为什么其大小却不相同呢?
    这里就存在内存对齐问题。

    规则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址0开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始。
    在这里插入图片描述

    如上图例,首先系统会将字符型变量a存入第0个字节,然后在存放整形变量b时,会以4个字节进行存储,由于第一个四字节模块已有数据,因此它会存入第二个四字节模块,也就是存入到4~8字节;同理,存放双精度型变量c时,由于其宽度为8,其存放时会以8个字节为单位存储,也就是会找到第一个空的且是8的整数倍的位置开始存储,上列中,由于头一个8字节模块已被占用,所以将c存入第二个8字节模块。

    结构体B因为与结构体A两个变量的类型发生交换,其测试结果发生变化。其大小为 8+8+4=20;但运行结果为24,这就用到规则二。

    == 规则二:在经过第一规则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。==
    在这里插入图片描述
    B结构体中,我们分析完后的存储长度为20字节,不是最宽元素长度8的整数倍,因此将它补齐到8的整数倍,也就是24。

    总结一下:
    结构体内存对齐规则
    原则1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,
    第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack
    指定的数值和这个数据成员自身长度中,比较小的那个进行。
    原则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,
    结构(或联合)本身也要进行对齐,对齐将按照#pragma pack
    指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
    原则3:结构体作为成员:如果一个结构里有某些结构体成员,
    则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

    展开全文
  • 1. 结构体内存对齐规则   对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值   vs中的默认值为8; Linux中的默认值为4; 原则1:数据成员的对齐规则(以最大的类型字节为单位)。   结构体(struct)的...

      在计算结构体类型变量的大小时,就涉及到了内存对齐问题。

    1. 结构体内存对齐规则

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

    • vs中的默认值为8;
    • Linux中的默认值为4;
    1. 原则1:数据成员的对齐规则(以最大的类型字节为单位)。
        结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在32位机为4字节,则要从4的整数倍地址开始存储)

    2. 原则2:结构体作为成员的对齐规则。
        如果一个结构体B里嵌套另一个结构体A,则结构体A应从offset为A内部最大成员的整数倍的地方开始存储。(struct B里存有struct A,A里有char,int,double等成员,那A应该从8的整数倍开始存储。),结构体A中的成员的对齐规则仍满足原则1、原则2。
      **(注意)**结构体A所占的大小为该结构体成员内部最大元素的整数倍,不足补齐;不是直接将结构体A的成员直接移动到结构体B中。

    3. 收尾工作
        结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

    示例1:

    struct
    {
    	int a;
    	short b;
    }A;
    //sizeof(A) = 8;
    
    struct
    {
    	int a;
    	char b;
    	short c;
    }A;
    //sizeof(A) = 8;
    
    struct
    {
    	char b;
    	int a;
    	short c;
    }A;
    //sizeof(A) = 12;
    
    struct A
    {
    	int a;
    	double b;
    	float c;
    };
    struct B
    {
    	char e[2];
    	int f;
    	double g;
    	short h;
    	struct A i;
    }B;
    //sizeof(B) = 48;
    
    struct A
    {
    	int a;
    	double b;
    	float c;
    };
    
    struct
    {
    	char e[2];
    	int f;
    	Int g;
    	short h;
    	struct A i;
    }B;
    //sizeof(B) = 40
    
    #pragma pack(2)  //指定对齐单位为2个字节
    typedef struct
    {
    	int a; 
    	char b;
    	short c;
    	char d;
    }A;
    //sizeof(A) = 10;
    

    2. 有关不完整类型的字节对齐(位域)

      使用位域的主要目的是压缩存储,其大致规则为:

    1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。
    2. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
    3. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
    4. 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++和gcc采取压缩方式;
    5. 如果位域字段之间穿插着非位域字段,则不进行压缩;
    6. 整个结构体的总大小为最宽基本类型成员大小的整数倍。

    示例2:

    //以 4 字节对齐
    struct A
    {
        int     a1:5; 
        int     a2:9; 
        char    c;
        int     b:4;
        short   s;
    }B;
    //sizeof(B) = 16
    
    #pragma pack(2)     //2字节对齐
    struct A
    {
    	int     a1 : 5;
    	int     a2 : 9;
    	char    c;
    	int     b : 4;
    	short   s;
    }B;
    //sizeof(B) = 12;
    
    struct  A
    {
    	int   a : 5;
    	int   b : 7;
    	int   c : 6;
    	int   d : 9;
    	char  e : 2;
    	int   x;
    }B;
    //sizeof(B) = 12
    

    3. 为什么存在内存对齐

    1. 平台原因(移植原因):不是所有硬件平台都能访问任意地址上的数据的;某些硬件平台只能在某些地址处区某些特定类型的数据,否则抛出硬件异常;
    2. 性能原因:数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐内存只需要一次访问;
    展开全文
  • 结构体内存对齐规则 一、什么是结构体内存对齐         结构体不像数组,结构体中可以存放不同类型的数据,它的大小也不是简单的各个数据成员大小之和,限于读取内存的...

    一、什么是结构体内存对齐

            结构体不像数组,结构体中可以存放不同类型的数据,它的大小也不是简单的各个数据成员大小之和,限于读取内存的要求,而是每个成员在内存中的存储都要按照一定偏移量来存储,根据类型的不同,每个成员都要按照一定的对齐数进行对齐存储,最后整个结构体的大小也要按照一定的对齐数进行对齐。

    二、对齐规则

    • 第一个成员在与结构体变量偏移量为0的地址。
    • 其他成员变量要对齐到对齐数(对齐数 = 编译器默认的一个对齐数与该成员大小的较小值)的整数倍的地址处。
    • Linux中默认为4,vs中的默认值为8。
    • 结构体总大小为最大对齐数的整数倍(每个成员变量除了第一个成员都有一个对齐数)。

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

    • 每个成员的偏移量 % 自己的对齐数 = 0
    • 结构体整体大小 % 所有成员最大对齐数 = 0
    • 结构体的对齐数是自己内部成员的对齐数中的最大对齐数

    三、举例说明

    // 平台VS2013下(默认对齐数为8)
    // 案例一
        struct S1
        {
            char c1;
            int i;
            short s2;
        };
        printf("%d\n", sizeof(struct S1)); // 12
    // 案例二
        struct S2
        {
            char c1;
            short s2;
            int i;
        };
        printf("%d\n", sizeof(struct S2)); // 8
    

    案例一分析

            char类型占1个字节,编译器默认对齐数为8,则该变量对齐数为1,实际偏移量为0
            int类型占4个字节,编译器默认对齐数为8,则该变量对齐数位4,偏移量应该为4的倍数,实际偏移量为4
            short类型占2个字节,编译器默认对齐数为8,则该变量对齐数2,偏移量应该为2的倍数,实际偏移量为8
            结构体整体的对齐数为所有成员的对齐数中最大的一个,对齐数为4
            结构体整体大小,按照上面数据占据空间大小,计算得结构体大小10字节。
            按照对齐规则,应该对齐到4的倍数,实际大小为12字节

    案例二分析

            char类型占1个字节,编译器默认对齐数为8,则该变量对齐数为1,实际偏移量为0
            short类型占2个字节,编译器默认对齐数为8,则该变量对齐数2,偏移量应该为2的倍数,实际偏移量为2
            int类型占4个字节,编译器默认对齐数为8,则该变量对齐数位4,偏移量应该为4的倍数,实际偏移量为4
            结构体整体的对齐数为所有成员的对齐数中最大的一个,对齐数为4
            结构体整体大小,按照上面数据占据空间大小,计算得结构体大小8字节。
            按照对齐规则,应该对齐到4的倍数,实际大小为8字节

    图形分析

    在这里插入图片描述

    四、为什么存在内存对齐

    平台移植型好

            不是所有的硬件平台都能访问任意地址上的数据;某些硬件平台只能只在某些地址访问某些特定类型的数据,否则抛出硬件异常,及遇到未对齐的边界直接就不进行读取数据了。

    cpu处理效率高

    在这里插入图片描述
            从上图可以看出,对应两种存储方式,若CPU的读取粒度为4字节:

    • 那么对于一个int 类型,若是按照内存对齐来存储,处理器只需要访存一次就可以读取完4个字节
    • 若没有按照内存对其来读取,如上图所示,就需要访问内存两次才能读取出一个完整的int 类型变量
    • 具体过程为,第一次拿出 4个字节,丢弃掉第一个字节,第二次拿出4个字节,丢弃最后的三个字节,然后拼凑出一个完整的 int 类型的数据。

    结构体内存对齐是拿空间换取时间的做法,提高效率

    展开全文
  • 一、为什么存在内存对齐 1、平台原因: 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因: 数据结构(尤其是栈)应该尽...

    一、为什么存在内存对齐

    1、平台原因:

    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

    2、性能原因:

    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅需要一次访问。

    二、对齐规则

    1、第一个成员在与结构体偏移量为0的地址处。

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

    对齐数 = 编译器默认的对齐数与该成员大小的较小值。(vs中默认值为0)

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

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

    主要规则就是前三条,第一条说的是第一个成员存放的位置,第二条说的是其他成员存放的位置,第三条规定了最后一个成员所占的字节。

    三、举几个实例

    1、

    我们可以根据地址画一下它的内存图,可以看出c1遵循第一条规则放在了和结构体偏移量为0的地址处;c2的对齐数为它自己的长度4和编译器默认的8的较小值,也就是4,根据第二条规则,放在4的整数倍处,也就是第五个字节到第八个字节处;  i 的对齐数为1,根据第二个规则,它就存放在第九个字节处,又根据第三条规则:结构体总大小为最大对齐数的整数倍,此结构体的最大对齐数为4,整数倍就是12,所以i后面又空了3个字节。

     

     2、

     把c2和i的类型交换一下后,我们可以看出总字节数变为了8,根据前三条规则也可以知道它们的具体的存储方式。可见将空间占用量小的成员放在一起可以节省空间。

    四、修改编译器的默认对齐数

    结构在对齐方式不合适的时候,我们可以用#pragma这个预处理指令来更改默认对齐数。

    比如上面的第二个代码把默认对齐数改为1后,它的总长度变为了6,没有了浪费字节的情况。

     

    展开全文
  • C语言--结构体内存对齐规则

    千次阅读 多人点赞 2021-01-17 21:28:47
    C语言结构体对齐规则: 结构体(struct)的数据成员,第一个数据成员存放的地址为结构体变量偏移量为0的地址处. 其他结构体成员自身对齐时,存放的地址为min{有效对齐值为自身对齐值, 指定对齐值} 的最小整数倍的地址...
  • 但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就是需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。   对齐的作用:  各个硬件平台对存储空间的处理上...
  • 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C Programming Language 一书中对于联合体是这么描述的:      1)联合体是一个结构;      ...
  • 2. 结构体内存对齐规则 1)第一个成员在与结构体偏移量为0的地址处。 2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。  注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。   ...
  • 结构体内存对齐规则 要想计算结构体的大小,首先得了解结构体的内存对齐规则。 第一个成员在与结构体变量偏移位为0的地址处 其他成员变量要对齐到对齐数的整数倍的地址处 对齐数 = 编译器默认的对齐数(VS为8、...
  • 内存对齐规则:  原则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素...
  • 0x00简介首先要知道结构体对齐规制1.第一个成员在结构体变量偏移量为0的地址处2.其他成员变量对齐到某个数字的整数倍的地址处对齐数=编辑器默认的一个对齐数与该成员大小的较小值vs中默认的值为8gcc 没有默认就是...
  • 结构体成员内存对齐规则

    千次阅读 2018-03-01 16:13:47
    关于结构体成员内存对齐,主要有以下三方面原则: 原则1:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是 紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都 会认为内存是...
  • 结构体内存对齐(如何计算结构体的大小)

    千次阅读 多人点赞 2021-03-03 20:04:07
    文章目录结构体内存对齐规则结构体大小计算 - 三步曲为什么存在内存对齐?设计结构体时的技巧修改默认对齐数 结构体内存对齐规则 我们知道,整型变量有自己的大小,浮点型变量有自己的大小,数组也有自己的大小,...
  • go结构体内存对齐

    2020-11-23 21:01:19
    由于内存对齐的原因,结构体实际占用字节数永远大于等于结构体所有字段字节数之和。没错,确实有正好相等的情况,后面我们会看到在一种什么样的机缘巧合之下他们会恰好相等。 对于结构体的每个字段,我们先来认识...
  • 1.如果没有内存对齐,有些数据可能要CPU的二次访问才能取到,因为CPU...2.如果采用默认对齐模数,则结构体内存对齐,内部对齐规则如下: 1)从第一个属性开始,偏移量为0 2)从第二个属性开始计算偏移,要放在 该类...
  • 要搞定如何正确地计算一个结构体的大小,我们就要深刻理解结构体内存对齐规则结构体内存对齐规则: 1.结构体的第一个成员永远在结构体起始位置偏移量为0的位置; 2.结构体成员从第二个成员开始,总是放在偏移...
  • C语言中结构体内存对齐规则 对齐规则: 内存偏移为该数据类型的最小整数倍 总体占用内存为结构体中最大数据类型的整数倍 举个????: 首先,要搞清楚每一种数据类型占用内存为多少,在这里,是针对64位Linux(macOs...
  • 对齐规则 (1) 第一个成员在与结构体变量偏移为0的地址处. (2) 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数:编译器默认的一个对齐数与该成员大小的较小值(vs中默认值为8,Linux中默认值为4)...
  • 内存对齐举例: 以下两个结构体: #include&amp;amp;amp;lt;iostream&amp;amp;amp;gt; using namespace std; struct A{ char a; int b; short c; }; struct B{ short c; char a; int b; }; int ...
  • 结构体内存对齐

    千次阅读 多人点赞 2018-08-19 00:49:41
    结构体内存对齐 先来看几个例题: 例1: struct S1 { char C1; int i; char C2; }; printf(&quot;%d\n&quot;, sizeof(struct S1)); 解析: char 为1个字节, int 为4个字节; char c1 从0偏移...
  • go 结构体内存对齐

    2021-11-20 20:42:18
    对齐规则 1、对于结构体成员变量: 某个成员的偏移量 = k * min(编译器对齐系数, 该成员类型长度) k >= 1 2、结构体完整大小也必须满足: min(k * max(编译器对齐系数, 最大成员类型长度)) k >= 1 ...
  • 主要给大家总结了关于C++面试题中结构体内存对齐计算问题的相关资料,文中通过示例代码介绍的非常详细,通过这些介绍的内容对大家在面试C++工作的时候,会有一定的参考帮助,需要的朋友们下面随着小编来一起学习学习...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,741
精华内容 6,696
关键字:

结构体内存对齐规则