精华内容
下载资源
问答
  • struct 内存对齐

    千次阅读 2018-04-12 11:56:20
    也许我们会遇到如下情况:#include&...struct A{ char a; int b; short c;};struct B{ short c; char a; int b;};int main(){ cout<<sizeof(A)<<endl; cou...

    也许我们会遇到如下情况:

    #include<iostream>
    using namespace std;
    struct A{
        char a;
        int b;
        short c;
    };

    struct B{
        short c;
        char a;
        int b;
    };
    int main(){
        cout<<sizeof(A)<<endl;
        cout<<sizeof(B)<<endl;
        return 0;

    }

    上面两个结构体A和B成员变量类型相同,但是占用的内存空间大小(单位:字节)却不一样

    ​ sizeof(A) = 12

    ​ sizeof(B) = 8

    造成这种问题的原因就是内存对齐。

    1、内存对齐的概念

    一种提高内存访问速度的策略,cpu在访问未对其的内存需要经过两次内存访问,而经过内存对齐一次就可以了。

    打个比方就是:操作系统在访问内存时,每次读取一定的长度(这个长度是系统默认的对其系数),程序中你也可以自己设定对齐系数,告诉编译器你想怎么对齐,可用#pargam pack(n),指定n为对其系数。但是当没有了内存对齐,cpu在访问一个变量时候,可能会访问两次,为什么呢? 

    32位cpu一次能最多处理的信息是32bit位,如果你没有指定对齐,我们假设这样的数据结构在内存中存在的情况

    typedef strutc test{
        char a;
        int b;
        char c;
    } 
    • 1
    • 2
    • 3
    • 4
    • 5

    对应的在内存中存放的方式可能是这样(假定32位下): 
    这里写图片描述

    那么,这样一来,取得这个int型变量需要经过两次的寻址拼凑成一个完整的4字节的数。这个过程还涉及到cpu指令集调用和总线的读写操作,如果真是没有对齐的话,效率会差到不知道哪儿去了。 
    所以这个内存对齐是必须遵守的,为了提高cpu访问效率和速度。

    2、内存对齐的原则:

    1. 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
    2. 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
    3. 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
     举个例子如下: 
    地址4可以放char(1)类型,可以放int(4)型,可以放short(2)型,但是不能存放double(8)型,仅仅因为4不是8的整数倍。 
    地址3能存放char型,但是其他int,short,double都不能存放。 
    有一个特殊地址,就是0,它可以是任何类型的整数倍,所以可以存放任何数据。 
    根据这个规则,那么在分配一大块包含很多变量的内存的时候,会产生很多碎片,具体到下面分析

    接下来,我们对这个结构体来进行一个分析:

    #include<stdio.h>
    #include<stdlib.h>
    typedef strutc test{
        char a;
        int b;
        double c;
        char d;
    } 
    
    int main(void)
    {
        STU s;
        printf("s的大小是 = %d\n",(int)sizeof(STU));    
        printf("s中a的起始地址是 %p\n",&(s.a));    
        printf("s中b的起始地址是 %p\n",&(s.b));
        printf("s中c的起始地址是 %p\n",&(s.c));
        printf("s中d的起始地址是 %p\n",&(s.d));
    
        return 0;
    }
    
    
    /*64位下
    s的大小是  = 24
    s中a的起始地址是 0x7ffd01319d10
    s中b的起始地址是 0x7ffd01319d14
    s中c的起始地址是 0x7ffd01319d18
    s中d的起始地址是 0x7ffd01319d20
    */
    • 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

    依照简单的4字节对齐(gcc默认是4字节对齐),首先的char在0上(其实也就是某个4的整数倍数上),之后int b在地址4上,一直延续到8,double c就在地址8上,之后sizeof必须是8的整数倍,之前是4+4+8 == 16,那这个char就只能存入一个8大小的内存中了,也就是4+4+8+8 == 24

    为什么这么算呢? 
    开始的可以根据内存的自然对齐求得,最后的char补7个空白是因为结构体的总大小,必须要是其内部最大成员的整数倍,不足的要补齐,像这里就是double 8个字节的整数倍,所以给最后的d补上了7个空白空间。这也是内存分配的3个原则之一。

    关于内存分配的其他两个规则如下: 
    1.结构体或union联合的数据成员,第一个数据成员是要放在offset == 0的地方,如果遇上子成员,要根据子成员的类型存放在对应的整数倍的地址上 
    2.如果结构体作为成员,则要找到这个结构体中的最大元素,然后从这个最大成员的整数倍地址开始存储(strutc a中有一个struct b,b里面有char,int,double….那b应该从8的整数倍开始存储)

    还需要注意一点:

    typedef struct stu{
        char a;
        int b;
        char ex;
        double c;
        char d;
    }STU;
    
    printf("STU的大小是 = %d\n",(int)sizeof(STU));  
    
    /*32位输出
    STU的大小是 = 24
    */
    
    /*64位输出
    STU的大小是 = 32
    */
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    计算一下出来的结果和输出是否正确: 
    32位:a( 4 )+b( 4 )+ex( 4 )+c( 4+4 )+d( 4 ) == 24 
    64位:a( 4 )+b( 4 )+ex( 8 )+c( 8 )+d( 8 ) == 32

    而为什么会出现这样的结果呢?准确一点为什么32位中的double变成了2个4字节而不是一个8?

    这需要结合之前说的内存的自然对齐,我们知道char遇到int型,产生3个空白,遇上double要产生7个空白。而这里32位中的char遇上double却只是产生了3个空白,是因为32位限制了一次只能读入4个字节数据处理,也就是说8字节的double被分成了2个4字节字符被处理,也可以说死了,32位平台下就定死了4字节对齐(当然你可以设定更小,但是没什么意义),接着说结构体,那结构体中最大的数就是4字节的了,sizeof(STU)也只需要遵守是4的整数倍即可。最后得到24字节。

    64位就按正常的计算。

    最后贴上这一段代码,是下面参考博文中某个作者总结的一段,只要能看懂这段代码就大抵上全部理解3个内存对其和分配原则

    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;
    }

    /*输出
    48 24
    */
    3、内存对齐的作用:
    1、平台原因(移植原因)
         A   不是所有的硬件平台都能访问任意地址上的任意数据的;
         B    某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
     2、性能原因:
         A   数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
         B   原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

    补充:
    我们知道,C++为了兼容C,保留了struct关键字,但是实际上C++中的struct是一个默认访问控制权限为public的class。C++标准规定:一个空类的大小为1个字节,因此在C++中,sizeof(空类或空结构体) = 1,在C语言中,sizeof(空结构体) = 0。

    展开全文
  • C++ struct内存对齐

    千次阅读 2017-03-31 09:53:29
    struct内存对齐

    一. 为何要内存对齐

    因为处理器读写数据,并不是以字节为单位,而是以块(2,4,8,16字节)为单位进行的。如果不进行对齐,那么本来只需要一次进行的访问,可能需要好几次才能完成,并且还要进行额外的merger或者数据分离。导致效率低下。更严重地,会因为cpu不允许访问unaligned address,就会报错,或者打开调试器或者dump core,比如sun sparc solaris绝对不会容忍你访问unaligned address,都会以一个core结束你的程序的执行。所以一般编译器都会在编译时做相应的优化以保证程序运行时所有数据都是存储在’aligned address’上的,这就是内存对齐的由来。

    二. 内存对齐

    结构体的内存布局依赖于CPU、操作系统、编译器及编译时的对齐选项。结构体内部成员的对齐要求,结构体本身的对齐要求。

    (一)成员对齐。对于结构体内部成员,通常会有这样的规定:各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。

    (二)整个结构体的对齐需求。要求结构体至少是其中的那个最大的元素大小的整数倍。因为有时候我们使用的是结构体数组,所以结构体的大小还得保证结构体数组中各个结构体满足对齐要求,同时独立的结构体与结构体数组中单个结构体的大小应当是一致的。

    (三)编译器的对齐指令。VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏 移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条 件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数。

    三. 举例

    struct MyStruct
    {
    char dda;
    double dda1;
    int type
    };

    struct MyStruct
    {
    char dda;//偏移量为0,满足对齐方式,dda占用1个字节;
    double dda1;//下一个可用的地址的偏移量为1,不是sizeof(double)=8
    //的倍数,需要补足7个字节才能使偏移量变为8(满足对齐
    //方式),因此VC自动填充7个字节,dda1存放在偏移量为8
    //的地址上,它占用8个字节。
    int type;//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍
    //数,满足int的对齐方式,所以不需要VC自动填充,type存
    //放在偏移量为16的地址上,它占用4个字节。
    };//所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构
    //的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof
    //(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为
    //sizeof(double)=8的倍数。

    所以该结构总的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。

    展开全文
  • struct内存对齐

    2017-07-10 22:06:08
    关于C++中的struct内存对齐,应该也是初学者比较疑惑的一个知识点,但是搞清楚之后会发现非常简单,这里解释一下struct内存到底怎么对齐。  主要记住以下两点: 1.各成员变量存放的起始地址相对于结构的起始地址...

           关于C++中的struct内存对齐,应该也是初学者比较疑惑的一个知识点,但是搞清楚之后会发现非常简单,这里解释一下struct内存到底怎么对齐。

           主要记住以下两点:

    1.各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数

    2.整个struct的内存大小需为struct中最大字节数变量的整数倍


    下面举个例子:

    struct A{

    int a;

    char b;

    short c;

    int d;

    }

    int型的a占4字节,char型的b占1字节,根据要点1,b的偏移量就是a的大小4字节,是b大小1字节的整数倍,因此已经对齐,再看short c的大小是2字节,相对于结构体起始内存偏移量是(4+1)=5字节,不是2的整数倍,因此这里需要插入1字节,成6字节,这样才是2字节的整数倍,最后看d,偏移量为8,已经是整数倍,现在总内存是12字节,是struct中最大字节变量的整数倍,不需要对齐,因此总的大小为12字节。

    展开全文
  • class struct 内存对齐

    2019-09-26 22:27:21
    class struct 内存对齐struct内存对齐class内存对齐 原则: 1、每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍 2、struct最终占用字节数为成员类型中最大占用字节数的整数倍 struct内存...

    class struct 内存对齐


    原则:
    1、每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍
    2、struct最终占用字节数为成员类型中最大占用字节数的整数倍

    struct内存对齐

    Demo1:占用17字节,由于必须是8的整数倍,所以实际占用24字节

    struct Stu
    {
        int id;									// 占用0~3
        double d;								// 占用8~15
        char c;							// 占用16
    };
    

    Demo2:占用16字节,是8的整数倍,实际占用16字节

    struct vpoet
    {
        char c;			// 占用0
        int id;			// 占用4~7
        double d;		// 占用8~15
    };
    

    总结:struct占用内存与元素顺序有关,建议按单个元素占用空间大小合理排序

    class内存对齐

    Demo1:空类占用1字节

    class Empty
    {
    }
    

    Demo2:虚函数占用一个指针的空间(参考博主:多继承和虚继承 & 虚函数),以下占用12字节(参考struct内存对齐机制)

    class CBase
    {
    public:
        CBase(void);
        virtual ~CBase(void);
    private:
        int   a;
        char *p;
    };
    

    Demo3:子类大小等于父类大小+子类成员大小(16字节)

    class CChild : public CBase
    {
    public:
        CChild(void);
        ~CChild(void);
    private:
        int b;
    };
    

    Demo4:静态数据成员被编译器放在程序的一个global data members中,它是类的一个数据成员.但是它不影响类的大小(8字节)

    class A
    {
      int a;
      static int b;
      virtual void FuncA();
    };
    
    展开全文
  • c++ struct 内存对齐

    千次阅读 2018-08-12 17:30:39
    结构体的内存布局依赖于cpu,操作系统,编译器以及编译时的选项。 考虑三点: 1.成员对齐 每个成员变量存放的位置相对于结构体起始位置的偏移量必须为该变量类型所占用字节数的倍数。 空缺的字节由编译器自动...
  • 主要给大家总结了关于C++面试题中结构体内存对齐计算问题的相关资料,文中通过示例代码介绍的非常详细,通过这些介绍的内容对大家在面试C++工作的时候,会有一定的参考帮助,需要的朋友们下面随着小编来一起学习学习...
  • 为什么要内存对齐 虽然所有的变量最后都会保存到特定的地址内存中去,但是相应的内存空间必须满足内存对齐的要求,主要基于存在以下两个原因: 硬件平台原因: 并不是所有的平台都能够访问任意地址上的任意数据,...
  • c/c++ struct内存对齐

    千次阅读 2013-11-23 18:42:29
    内存对齐 结构体的内存布局依赖于CPU、操作系统、编译器及编译时的对齐选项。结构体内部成员的对齐要求,结构体本身的对齐要求。最重要的有三点 (一)成员对齐。对于结构体内部成员,通常会有这样的规定:各成员...
  • C# Struct内存对齐

    2020-10-13 16:02:59
    内存对齐的方式有三种,测试需要引用命名空间using System.Runtime.InteropServices; namespace System.Runtime.InteropServices { [ComVisible(true)] public enum LayoutKind { Sequential = 0, Explicit = 2...
  • 结构体struct内存对齐

    2020-03-15 01:23:47
    结构体内存对齐是因为,对于计算机来说读取4个字节的内存空间比读取1、2、3个字节的要更高效。但是也根据编译器而定,而且自己也可以改变对齐内存的大小用 预编译命令#pragma pack (n) 规则: 1.第一个元素...
  • 在c/c++中内存对齐是个经常遇到的问题,现在的CPU一次读取64bit,所以Struct编译时会自动8byte对齐。 c#同样的结构体也是8byte对齐。 using System; struct ss { public int a; // 4字节 // public int aa; // 4...
  • C语言中,struct类型在内存中占有大小根据编译器的不同而不同。 现在测试的是以vc++6.0编译环境的结果。 在vc++6.0下,我们知道各种数据类型的占用大小不一样。 char:1字节 int:4字节 short:2字节 float:4...
  • [笔试题]struct内存对齐

    千次阅读 2011-11-03 21:21:21
    结构体的内存对齐实际上是硬件工程师的事,但是由于笔试经常考,而且我们在实际项目中由于设置的对齐方式不对曾经导致过在不同机器上不能移植的问题。所以有必要了解一下。  1.为什么需要内存对齐:因为计算机一次...
  • sizeof与struct——求结构体大小的计算方法 sizeof浅析(一)——求结构体大小 这篇文章讲了sizeof求结构体大小的计算方法,并给出可以套用的准则: 一、存储变量时地址要求对齐,编译器在编译程序时会遵循两条...
  • 字节对齐原则 在系统默认的对齐方式下:每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍,且最终占用字节数为成员类型中最大占用字节数的整数倍。 struct struct1 { char a; int ...
  • C/C++中关于struct内存对齐问题

    千次阅读 2015-05-25 23:28:24
    就这篇写的清晰明了。做如下总结: ...1、对齐值如何计算 ...① 如果没有指定对齐值,则对齐值为成员变量中最大的那个值。...② 如果指定的对齐值(#pragam pack(value)// 2,4,6,8....),则对齐值为
  • 内存对齐1. 成员对齐:对于结构体的每个成员,起始地址的偏移量必须为该变量类型所占字节的整数倍。 2. 结构体对齐:结构体中占字节最多的成员叫边界成员,整个结构体所用空间必须是边界成员所占字节的整数倍。 3. ...
  • struct结构体的内存对齐规则: 1、结构体中第一个成员在 与结构体变量偏移量为0 的位置; 2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处; 注意: (1) 对齐数 = 编译器默认的一个对齐数 与 该成员所占...
  • go结构体内存对齐

    2020-11-23 21:01:19
    由于内存对齐的原因,结构体实际占用字节数永远大于等于结构体所有字段字节数之和。没错,确实有正好相等的情况,后面我们会看到在一种什么样的机缘巧合之下他们会恰好相等。 对于结构体的每个字段,我们先来认识...
  • 关于结构体的内存对齐关于结构体的内存对齐关于结构体的内存对齐
  • Golang优化之内存对齐

    千次阅读 2018-12-18 03:57:12
    话说今天在用uintptr进行指针运算的时候,突然想起来有个内存对齐的东西,那么对这个uintptr计算是否会有影响? 带着疑问,开始吧。 你将获得以下知识点: 1.什么是内存对齐? 2.为什么需要内存对齐? 3.如何进行...
  • 一、存在内存对齐的原因 1、平台原因 不是所有硬件平台都能够访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因(主要原因) 数据结构(尤其是栈)应该...
  • Struct与Union以及内存对齐问题

    千次阅读 2019-09-24 23:18:04
    struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之和。 在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。Union变量的长度等于最长的成员的...
  • 结构体内存对齐

    千次阅读 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偏移...
  • C++:struct和union 内存字节对齐问题

    千次阅读 2016-11-23 21:16:23
    struct内存对齐问题1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要...
  • struct内存对齐 详解

    2012-05-23 23:30:56
    结构体对齐指的是:编译器向结构体插入无用内存的能力,插入无用内存使得结构体成员以最佳方式对齐,从而得到更高的效能。当基本数据类型以字节地址(几倍于自身大小)存储时,很多处理器能够获得最佳效能。 以下是...
  • 为什么要进行结构体内存对齐

    千次阅读 多人点赞 2018-08-10 21:59:12
    结构体内存对齐 什么是结构体内存对齐 结构体不像数组,结构体中可以存放不同类型的数据,它的大小也不是简单的各个数据成员大小之和,限于读取内存的要求,而是每个成员在内存中的存储都要按照一定偏移量来存储...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 55,659
精华内容 22,263
关键字:

struct内存对齐