精华内容
下载资源
问答
  • 本文详细讲述了C语言程序设计中内存对其的概念与用法。分享给大家供大家参考之用。具体如下: 一、字节对齐基本概念 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址...
  • C语言内存对齐规则

    2020-06-14 07:35:42
    为什么要内存对齐内存对齐的根本原因是由于处理器访问内存的方式决定的,以ARM 32位处理器为例,地址总线为32位,处理器访问的内存地址只能是4的倍数,如果一个int 类型的变量占用内存地址0、1、2、3字节空间,则...

    为什么要内存对齐,内存对齐的根本原因是由于处理器访问内存的方式决定的,以ARM 32位处理器为例,地址总线为32位,处理器访问的内存地址只能是4的倍数,如果一个int 类型的变量占用内存地址0、1、2、3字节空间,则处理器从0地址一次就可将数据去除,如果该int类型从地址空间2开始存储,占内存地址2、3、4、5字节空间,则处理器需要先访问0地址空间取出数据的高8位,再访问4地址空间取出数据的低8位,让后再将高低位数据组合在一起,这样的话处理器的效率就慢了一倍。因此我们在定义变量使用时,编译器会自动使分配的变量进行4字节对齐,以提高编译器的效率。

    我门看一下,编译器字节对齐的相应规则:

    1. 对于int、char、short、float、double等单个的数据类型,不需要我门去关心,编译器在分配空间时,就已经保证是4字节对齐。

    2. 对于结构体、联合、类等自定义数据类型,编译器在分配内存空间时,会对结构体进行填充,保证结构体内部成员的字节边界对齐和结构体整体内存空间的对齐。毫无疑问这样会提高效率,但是有些时候我们不希望结构体进行对齐,例如我使用结构体定义了一帧数据.

    struct message

    {

    unsigned char type;

    unsigned short len;

    unsigned int data;

    }Tmsg;

    struct Tmsg msg;

    像上述的结构体,编译器在分配内存空间时,会对结构体进行填充,结构体的实际长度并不是1+2+4 = 7,而是2+2+4 = 8;在type成员和len成员之间编译器会添加一个字节的填充,加入我把这帧数据通过网络发到服务器上send(ip,port,&msg,sizeof(Tmsg)),那么服务器可能就会收到带有填充的数据帧,在进行数据解析时就会出现错误。这时候我们就需要去指定结构体进行一字节对齐。

    #pragma pack(1)

    struct message

    {

    unsigned char type;

    unsigned short len;

    unsigned int data;

    }Tmsg;

    #pragma pack()

    3. 数组内存对齐

    编译器自身的malloc函数分配的内存空间时8字节对齐的,但是我们自定义的内存分配函数是无法保证内存对齐的,需要我们在内存池数组前添加__align(4),来保证数据空间的内存对齐。

    __align(4) u8 mem1base[MEM1_MAX_SIZE];

    这点是很重要的特别是使用DMA进行数据传输时,如果使用了内存未对齐的内存,可能会出问题。

    4. 自定义数据类型(结构体等)编译器分配内存对齐规则

    结构体成员对齐规则:结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

    结构体自身对齐规则:结构整体的对齐,则按照结构体中最大的数据成员和#pragma pack指定值 之间,较小的那个进行。

    5. 结构体内存对齐规则修改:我们可以使用__align(n)(常用于数组内存对齐修饰),#pragma pack(n)(常用于结构体内存对齐修饰)在改变编译器的内存对齐规则。

    方法一:
    使用#pragma pack(n),指定c编译器按照n个字节对齐;
    使用#pragma pack(),取消自定义字节对齐方式。

    方法二:
    __attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
    __attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

    比如:

    typedef struct

    {

      ...

    }__attribute__((aligned(4))) param_t;

     

    展开全文
  • 第一步:确认对齐字节 第二步:填充内存字节,别处看到的一句话:如果一行中剩下的空间不足以填充某成员变量,则该成员变量在分配内存时会另起一行分配。 这里一行的空间就是对齐字节数 两种方式修改编译器默认对齐...

    第一步:确认对齐字节
    第二步:填充内存字节,别处看到的一句话:如果一行中剩下的空间不足以填充某成员变量,则该成员变量在分配内存时会另起一行分配。 这里一行的空间就是对齐字节数

    两种方式修改编译器默认对齐字节数:
    1)如下
    #pragma pack (16)
    struct st_s{
    char a;
    int b;
    };
    #pragma pack ()
    修改值a = 16;
    默认值b = 结构体中占内存最大的字节长度,这里就是int类型的长度,就是4;
    那么实际对齐值就是min(a, b),就是4,
    所以结果sizeof(struct st_s) = 8;

    2)
    struct st_s{

        char a;
        int  b;
    

    };
    __attribute((aligned (16)));
    修改值a = 16;
    默认值b = 结构体中占内存最大的字节长度,这里就是int类型的长度,就是4;
    和1)不同的是,这个时候的对齐值就不是最小值了,而是按照修改值;
    所以实际对齐值就是16,按照第二步说的,如果一行中剩下的空间不足以填充某成员变量,则该成员变量在分配内存时会另起一行分配,在这个例子中,char a占4字节,b紧跟其后占4字节,不用换新行,一行就可以填充两个成员的内存;
    所以结果sizeof(struct st_s) = 16;

    展开全文
  • 内存对齐的初步讲解 内存对齐可以用一句话来概括: “数据项只能存储在地址是数据项大小的整数倍的内存位置上” 例如int类型占用4个字节,地址只能在0,4,8等位置上。 例1: 代码如下:#include <stdio>struct xx{ ...
  • C语言内存对齐方式

    2021-05-25 10:05:01
    这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式。 #pragma pack (n) 作用:C编译器将按照n个字节对齐。 #pragma pack () 作用:取消自定义字节对齐方式。 #...

    #pragma pack(push,1)与#pragma pack(1)的区别(转)
    这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式。

    #pragma pack (n) 作用:C编译器将按照n个字节对齐。
    #pragma pack () 作用:取消自定义字节对齐方式。

    #pragma pack (push,1) 作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐

    #pragma pack(pop) 作用:恢复对齐状态

    因此可见,加入push和pop可以使对齐恢复到原来状态,而不是编译器默认,可以说后者更优,但是很多时候两者差别不大

    如:

    #pragma pack(push) //保存对齐状态

    #pragma pack(4)//设定为4字节对齐

    相当于 #pragma pack (push,4)

    #pragma pack (1) 作用:调整结构体的边界对齐,让其以一个字节对齐;<使结构体按1字节方式对齐>

    #pragma pack ()

    例如:

    #pragma pack(1)
    
    struct sample
    {
    char a;
    double b;
    };
    
    #pragma pack()
    

    注:若不用#pragma pack(1)和#pragma pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐,则sizeof(sample)==16.成员char a占了8个字节(其中7个是空字节);若用#pragma pack(1),则sample按1字节方式对齐sizeof(sample)==9.(无空字节),比较节省空间啦,有些场和还可使结构体更易于控制。

    应用实例

    在网络协议编程中,经常会处理不同协议的数据报文。一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改起来也比较麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这一特性定义自己的协议结构,通过访问结构的成员来获取各种信息。这样做,不仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,其它程序无需修改,省时省力。下面以TCP协议首部为例,说明如何定义协议结构。其协议结构定义如下:

    #pragma pack(1) // 按照1字节方式进行对齐
    struct TCPHEADER
    {
         short SrcPort; // 16位源端口号
         short DstPort; // 16位目的端口号
         int SerialNo; // 32位序列号
         int AckNo; // 32位确认号
         unsigned char HaderLen : 4; // 4位首部长度
         unsigned char Reserved1 : 4; // 保留6位中的4位
         unsigned char Reserved2 : 2; // 保留6位中的2位
         unsigned char URG : 1;
         unsigned char ACK : 1;
         unsigned char PSH : 1;
         unsigned char RST : 1;
         unsigned char SYN : 1;
         unsigned char FIN : 1;
         short WindowSize; // 16位窗口大小
         short TcpChkSum; // 16位TCP检验和
         short UrgentPointer; // 16位紧急指针
    };
    #pragma pack()
    
    展开全文
  • C语言内存对齐和结构补齐

    万次阅读 多人点赞 2018-05-12 11:55:52
    首先我们先看看下面的C语言的结构体:[cpp] view plaincopytypedef struct MemAlign { int a; char b[3]; int c; }MemAlign; 以上这个结构体占用内存多少空间呢?也许你会说,这个简单,计算每个类型的...

    首先我们先看看下面的C语言的结构体:

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. typedef struct MemAlign  
    2. {  
    3.     int a;  
    4.     char b[3];  
    5.     int c;  
    6. }MemAlign;  

        以上这个结构体占用内存多少空间呢?也许你会说,这个简单,计算每个类型的大小,将它们相加就行了,以32为平台为例,int类型占4字节,char占用1字节,所以:4 + 3 + 4 = 11,那么这个结构体一共占用11字节空间。好吧,那么我们就用实践来证明是否正确,我们用sizeof运算符来求出这个结构体占用内存空间大小,sizeof(MemAlign),出乎意料的是,结果居然为12?看来我们错了?当然不是,而是这个结构体被优化了,这个优化有个另外一个名字叫“对齐”,那么这个对齐到底做了什么样的优化呢,听我慢慢解释,再解释之前我们先看一个图,图如下:

        相信学过汇编的朋友都很熟悉这张图,这张图就是CPU与内存如何进行数据交换的模型,其中,左边蓝色的方框是CPU,右边绿色的方框是内存,内存上面的0~3是内存地址。这里我们这张图是以32位CPU作为代表,我们都知道,32位CPU是以双字(DWORD)为单位进行数据传输的,也正因为这点,造成了另外一个问题,那么这个问题是什么呢?这个问题就是,既然32位CPU以双字进行数据传输,那么,如果我们的数据只有8位或16位数据的时候,是不是CPU就按照我们数据的位数来进行数据传输呢?其答案是否定的,如果这样会使得CPU硬件变的更复杂,所以32位CPU传输数据无论是8位或16位都是以双字进行数据传输。那么也罢,8位或16位一样可以传输,但是,事情并非像我们想象的那么简单,比如,一个int类型4字节的数据如果放在上图内存地址1开始的位置,那么这个数据占用的内存地址为1~4,那么这个数据就被分为了2个部分,一个部分在地址0~3中,另外一部分在地址4~7中,又由于32位CPU以双字进行传输,所以,CPU会分2次进行读取,一次先读取地址0~3中内容,再一次读取地址4~7中数据,最后CPU提取并组合出正确的int类型数据,舍弃掉无关数据。那么反过来,如果我们把这个int类型4字节的数据放在上图从地址0开始的位置会怎样呢?读到这里,也许你明白了,CPU只要进行一次读取就可以得到这个int类型数据了。没错,就是这样,这次CPU只用了一个周期就得到了数据,由此可见,对内存数据的摆放是多么重要啊,摆放正确位置可以减少CPU的使用资源。

    那么,内存对齐有哪些原则呢?我总结了一下大致分为三条:
    第一条:第一个成员的首地址为0
    第二条:每个成员的首地址是自身大小的整数倍
           第二条补充:以4字节对齐为例,如果自身大小大于4字节,都以4字节整数倍为基准对齐。
    第三条:最后以结构总体对齐。
            第三条补充:以4字节对齐为例,取结构体中最大成员类型倍数,如果超过4字节,都以4字节整数倍为基准对齐。(其中这一条还有个名字叫:“补齐”,补齐的目的就是多个结构变量挨着摆放的时候也满足对齐的要求。)

        上述的三原则听起来还是比较抽象,那么接下来我们通过一个例子来加深对内存对齐概念的理解,下面是一个结构体,我们动手算出下面结构体一共占用多少内存?假设我们以32位平台并且以4字节对齐方式:

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. #pragma pack(4)  
    2. typedef struct MemAlign  
    3. {  
    4.     char a[18];  
    5.     double b;     
    6.     char c;  
    7.     int d;    
    8.     short e;      
    9. }MemAlign;  
    下图为对齐后结构如下:

    我们就以这个图来讲解是如何对齐的:
    第一个成员(char a[18]):首先,假设我们把它放到内存开始地址为0的位置,由于第一个成员占18个字节,所以第一个成员占用内存地址范围为0~18。
    第二个成员(double b):由于double类型占8字节,又因为8字节大于4字节,所以就以4字节对齐为基准。由于第一个成员结束地址为18,那么地址18并不是4的整数倍,我们需要再加2个字节,也就是从地址20开始摆放第二个成员。
    第三个成员(char c):由于char类型占1字节,任意地址是1字节的整数倍,所以我们就直接将其摆放到紧接第二个成员之后即可。
    第四个成员(int d):由于int类型占4字节,但是地址29并不是4的整数倍,所以我们需要再加3个字节,也就是从地址32开始摆放这个成员。
    第五个成员(short e):由于short类型占2字节,地址36正好是2的整数倍,这样我们就可以直接摆放,无需填充字节,紧跟其后即可。
        这样我们内存对齐就完成了。但是离成功还差那么一步,那是什么呢?对,是对整个结构体补齐,接下来我们就补齐整个结构体。那么,先让我们回顾一下补齐的原则:“以4字节对齐为例,取结构体中最大成员类型倍数,如果超过4字节,都以4字节整数倍为基准对齐。”在这个结构体中最大类型为double类型(占8字节),又由于8字节大于4字 节,所以我们还是以4字节补齐为基准,整个结构体结束地址为38,而地址38并不是4的整数倍,所以我们还需要加额外2个字节来填充结构体,如下图红色的就是补齐出来的空间:

    到此为止,我们内存对齐与补齐就完毕了!接下来我们用实验来证明真理,程序如下:

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. #include <stdio.h>  
    2. #include <memory.h>  
    3.   
    4. // 由于VS2010默认是8字节对齐,我们  
    5. // 通过预编译来通知编译器我们以4字节对齐  
    6. #pragma pack(4)  
    7.   
    8. // 用于测试的结构体  
    9. typedef struct MemAlign  
    10. {  
    11.     char a[18]; // 18 bytes  
    12.     double b;   // 08 bytes   
    13.     char c;     // 01 bytes  
    14.     int d;      // 04 bytes  
    15.     short e;    // 02 bytes  
    16. }MemAlign;  
    17.   
    18. int main()  
    19. {  
    20.     // 定义一个结构体变量  
    21.     MemAlign m;  
    22.     // 定义个以指向结构体指针  
    23.     MemAlign *p = &m;  
    24.     // 依次对各个成员进行填充,这样我们可以  
    25.     // 动态观察内存变化情况  
    26.     memset( &m.a, 0x11, sizeof(m.a) );  
    27.     memset( &m.b, 0x22, sizeof(m.b) );  
    28.     memset( &m.c, 0x33, sizeof(m.c) );  
    29.     memset( &m.d, 0x44, sizeof(m.d) );  
    30.     memset( &m.e, 0x55, sizeof(m.e) );  
    31.     // 由于有补齐原因,所以我们需要对整个  
    32.     // 结构体进行填充,补齐对齐剩下的字节  
    33.     // 以便我们可以观察到变化  
    34.     memset( &m, 0x66, sizeof(m) );  
    35.     // 输出结构体大小  
    36.     printf( "sizeof(MemAlign) = %d"sizeof(m) );  
    37. }  

    程序运行过程中,查看内存如下:

    其中,各种颜色带下划线的代表各个成员变量,蓝色方框的代表为内存对齐时候填补的多余字节,由于这里看不到补齐效果,我们接下来看下图,下图篮框包围的字节就是与上图的交集以外的部分就是补齐所填充的字节。

    在最后,我在谈一谈关于补齐的作用,补齐其实就是为了让这个结构体定义的数组变量时候,数组内部,也同样满足内存对齐的要求,为了更好的理解这点,我做了一个跟本例子相对照的图:

    展开全文
  • C语言内存对齐.pdf

    2021-10-06 17:26:04
    C语言内存对齐.pdf
  • 计算机的内存都是以字节为单位来划分的,CPU一般都是通过地址总线来访问内存的,一次能处理几个字节,就命令地址总线去访问几个字节,32位的CPU一次能处理4个字节,就命令地址总线一次读取4个字节,读少了浪费主频,...
  • 4. C语言内存对齐,提高寻址效率 5. 内存分页机制,完成虚拟地址的映射 6. 分页机制究竟是如何实现的? 7. MMU部件以及对内存权限的控制 8. Linux下C语言程序的内存布局(内存模型) 9. Windows下C语言程序的内存...
  • C语言内存对齐

    千次阅读 2012-04-05 20:54:50
    在解释内存对齐的作用前,先来看下内存对齐的规则: 1、 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。 ...
  • 详解C语言内存对齐

    千次阅读 多人点赞 2017-11-01 21:22:16
    C语言里有一个机制是内存对齐,当然不止C语言,包括其他的编程语言都会有内存对齐机制,否则编译出来的软件无法正常运行,至于为什么呢?众所周知,在内存中,所有的数据都是按字节为最小单位存储的,存储单位称为...
  • 内存对齐:结构体成员存放的地址要能整除该成员本身的大小 内存对齐的原则: 1.前面所有成员的大小相加,应该是当前成员大小的倍数 2.整个结构体的大小应该能整除该结构体中单个最大成员的倍数 *ps 每个数据类型的...
  • C语言——内存对齐总结

    千次阅读 2018-06-15 21:39:27
    1、什么是内存对齐? 将程序中的每个数据单元安排在适当的位置上(这是编译器干的事) 2、需要内存对齐的原因 不是所有的硬件平台都能访问任意地址上的任意数据(某些硬件平台只能在某些地址处取某些特定类型...
  • c语言内存对齐

    2013-03-28 21:54:57
    c语言中存在着内存对齐问题,在struct存储中尤为明显,这里先介绍一种情况,以后接着补充。 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; typedef unsigned long long int u...
  •   在计算结构体类型变量的大小时,就涉及到了内存对齐问题。 1. 结构体内存对齐规则   对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值   vs中的默认值为8; Linux中的默认值为4; 原则1:数据成员...
  • c语言内存对齐问题

    2016-10-10 20:19:32
    计算机为了提高工作效率,一般要求内存中的数据存放在特定的位置,使计算机用最少的机器周期便可以访问到这个数据,这就是c语言中的内存对齐问题。 这里以 int 型数据为例,如果内存中的数据按照4字节对齐存储,则...
  • C语言内存对齐

    千次阅读 2016-05-09 14:07:32
    相信大家都看过金庸的武侠小说,小说里那些大侠凭借一门绝世武功就可以打遍天下无敌手,而我们今天要讲的内存对齐术就相当于武侠小说里的绝世武功,理解它就可以了解结构体是如何在内存中存储的啦!本文就以结构体中...
  • c语言内存对齐小技巧

    2020-04-04 17:21:40
    如果需要改变机器或者编译器默认的对齐方式,可以采用: #pragma pack(4)//设置默认对齐数为4 如果需要使用默认的则: #pragma pack()
  • 接上一篇:C语言内存对齐详解(1)  VC对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。VC 中提供了#pragma pack(n...
  • 而在C语言中自定义的数据类型(例如结构体)占用的内存大小可能不满足4或8的整数倍,则会出现同一变量需要两次读取才能读完的情况,所以往往采用内存对齐来提高访问效率(以空间换时间)。 内存对齐规则 对于结构体...
  • 一、存在内存对齐的原因 1、平台原因 不是所有硬件平台都能够访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因(主要原因) 数据结构(尤其是栈)应该...
  • C语言-浅谈内存对齐

    2019-04-05 13:37:37
    内存对齐: 我们先来看一个现象,首先定义一个包含int、char、short三种基本类型的结构体,使用sizeof得到结构体实际占用内存为8个字节,这比直观计算的结构体内所有基本类型所占内存之和(4+1+2 = 7)要大,这就是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,034
精华内容 14,813
关键字:

c语言内存对齐

c语言 订阅