精华内容
下载资源
问答
  • 内存对齐方式
    2019-11-24 16:50:14

    问题解答https://www.cnblogs.com/jijiji/p/4854581.html

    更多相关内容
  • 结构体及内存对齐方式

    千次阅读 2022-03-31 17:54:47
    结构体基础 结构体就是一些成员的集合,结构体的每一个成员可以是整型、...要知道,位段的内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的。

    结构体基础

    结构体就是一些成员的集合,结构体的每一个成员可以是整型、数组、指针、结构体等不同的类型。

    下面是一个简单的结构体结构,包含了类型声明struct Stu、成员、结构体变量s1的声明。

    struct Stu {  //类型
    	//成员
    	char name[20];
    	int age;
    	char sex[10];
    }s1; //结构体变量
    

    我们可以像上面那样声明一个结构体变量,也可以像下面这样单独声明。

    struct Stu s2;
    

    struct是结构体关键字,Stu是结构体标志,两者构成了结构体类型。上面的语句表示为struct Stu类型的结构体声明了一个变量s1。下面是对s1的赋值操作,可以在声明结构体变量的时候直接赋值。

    struct Stu s1 = { "panghutx",20,"male" };
    

    在声明结构体时,我们可以对结构体不完全声明。

    struct{
        int a;
        char b;
        double c; 
    } a;
    struct{
        int a;
        char b;
        double c; 
    } *P;
    

    以上就不完全声明了两个结构体,我们称之为匿名结构体类型。结构体变量a和*p具有相同的成员,但它们是两个完全不同的类型。当我们尝试如下代码时,会出现警告。

    *p = &a;
    

    在这里插入图片描述

    说到结构体,我们难免提到一个关键字typedef,用于定义新的类型(或类型重命名)。我们在学习链表时可能会看到这样的结构,下面这段代码是对struct Node重命名为Node.而且还在结构体中引用了自己。

    typedef struct Node
    {
    int data;
    Node* next;
    }Node;
    

    切记在结构体自引用时不要使用匿名结构体,否则就是在定义新类型的时候引用了新类型,这是错误的。

    再看下面的写法,定义了两个新类型,Node*pNode,Node我们已经知道是对struct Node进行重命名,而*pNode是对struct Node*的重命名。

    typedef struct Node
    {
    int data;
    Node* next;
    }Node,*pNode;
    

    结构体内存对齐

    结构体的大小不是单纯的各元素相加,因为主流计算机使用的是32bit字长的CPU,那么取4个字节数要比1个高效,所以结构体存在内存对齐。每个编译器都有自己的对齐系数,程序员也可以通过预编译命令来改变默认对齐数。

    #pragma pack(n) //n为修改的对齐系数
    

    对齐规则:

    ①首个成员放在0ffset(偏移量)为0的位置,其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

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

    ②结构体总大小为各元素最大对齐数的整数倍。

    举个例子,计算下面结构体的大小是多少。

    struct S1
    {
    char c1;
    int i;
    char c2;
    };
    

    假设编译环境默认4字节对齐。

    c1是结构体首个元素,直接放到偏移量为0的位置,占1个字节;i自身大小为4字节,默认对齐4字节,因此对齐数就是四字节,将其放到对齐数整数倍的位置,也就是4偏移量的位置。c2自身大小1字节,默认对齐数4,因此对齐数是1,将其放到对齐数整数倍的位置,也就是int的后面。

    0~8偏移量,那么该结构体为9个字节,对吗?别忘了规则②,结构体总大小是各元素最大对齐数的整数倍。结构体内最大对齐数的元素是int,对齐数是4,9不是4的整数倍,再开辟3个字节。

    综上该结构体大小为12字节。

    在这里插入图片描述

    结构体位段

    c语言允许在一个结构体中以位为单位来指定成员长度,利用位段能够节约空间。

    struct A
    {
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;
    };
    

    A就是1个位段,它的大小为8个字节,想知道为什么是8个字节,要知道它的内存分配。

    • 位段的成员可以是 int unsigned int signed int或者是char (属于整形家族)类型
    • 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
    • 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

    调试下面代码,我们可以看一下空间是如何开辟的。

    struct S
    {
    char a:3;
    char b:4;
    char c:5;
    char d:4;
    };
    struct S s = {0};
    s.a = 10;
    s.b = 12;
    s.c = 3;
    s.d = 4;
    

    在这里插入图片描述

    我在vs2019环境下调试,和vs2013结果一样。先开辟一字节,从低位开始存数据,存不下时舍弃剩余位,再开辟一字节空间。

    以上存储方式只能代表vs环境下,其他环境不确定。要知道,位段的内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的。

    展开全文
  • 1. 内存对齐方式虽然所有的变量最后都会保存在特定地址的内存中,但相应的内存空间必须满足内存对齐的要求。主要出于两个方面的原因: (1) 平台原因: 不是所有的硬件平台(特别是嵌入式系统中使用的低端处理器)...

    1. 内存对齐方式

    虽然所有的变量最后都会保存在特定地址的内存中,但相应的内存空间必须满足内存对齐的要求。主要出于两个方面的原因:
    (1) 平台原因:
    不是所有的硬件平台(特别是嵌入式系统中使用的低端处理器)都能访问任意地址上的任意数据,某些硬件平台只能访问对齐的地址,否则会出现硬件异常。
    (2) 性能原因:
    如果数据存放在未对齐的内存空间中,则处理器访问变量时需要做两次内存访问,而对齐的内存访问仅需一次访问。

    在32位微处理器中,处理器访问内存都是按照32位进行的,即一次读取或写入都是4个字节,比如地址0x0~0xF这16字节的内存,对于微处理器来说,不是将其看做16个单一字节,而是4个块,每块4个字节。如下图
    这里写图片描述

    显然,只能从0x0、0x4、0x8、0xC等地址为4的整数倍的内存中一次取出4个字节,并不能从任意地址开始一次读取4个字节。假定将一个占用4个字节的int类型的数据存放在地址0开始的4字节内存中,其示意图如下
    这里写图片描述
    由于int类型数据存放在块0中,因此CPU仅需一次内存访问即可完成对该数据的读取或写入。反之,如果将int类型数据存放在地址1开始的4字节内存空间中,其示意图如下
    这里写图片描述
    此时,数据存放在块0和块1两个块中,若要完成对该数据的访问,必须经过两次内存访问,先访问块0得到数据的3个字节,再通过访问块1得到该数据的1个字节,最后通过运算,将这几个字节合并为一个完整的int型数据。由此可见,若数据存储在未对齐的内存空间中,将大大降低CPU的效率。但在某些特定的微处理器中,它根本不愿意干这种事情,这种情况下,就出现系统异常,直接崩溃了。

    2. 结构体的存储

    我们知道,数组是相同类型有序数据的集合,但很多时候需要将不同类型的数据捆绑在一起作为一个整体对待,使程序设计更方便。在C语言中,这样一组数据被称为结构体。其内存对齐的规则如下:
    (1) 结构体各个成员变量的内存空间的首地址必须是“对齐系数”和“变量实际长度”中较小者的整数倍。“对齐系数”是【#pragma pack指定的数值】、【未指定#pragma pack时,系统默认的对齐模数(32位系统为4字节,64位为8字节)】。假设要求变量的内存空间要求按照4字节对齐,则内存空间的首地址必须是4的整数倍,满足条件的地址为0x0, 0x4, 0x8, 0xC…
    (2) 对于结构体,在其各个数据成员都完成对齐后,结构体本身也需要对齐,即结构体占用的总大小应该为“对齐系数”和“最大数据成员长度”中较小值的整数倍。

    如下的结构体,在32位机器上编译,其成员数据的总长度为4+2+3+4+1+8 = 22(字节)

    #pragma pack(4)
    struct TEST
    {
        long a;         //4
        short b;        //2
        char c[3];      //3
        float d;        //4
        char e;         //1
        double f;       //8
    }test;
    

    有如下的测试程序

    int main(void)
    {
        short len = sizeof(test);
        printf("test length is %d.\n", len);
        return 0;
    }

    下面是输出结果,结果表明结构体占用28个字节的内存,大于22字节。
    这里写图片描述
    其实,正是由于内存对齐的原因造成了这种现象,下图是每个变量在内存的分布图,其中空白部分是内存弃用部分,这些浪费空间的前面,存放的都是char型数据,由于char型数据只占用一个字节,往往使得其紧接着的空间不能被其它长度更长的数据使用。
    这里写图片描述

    为了降低内存浪费的概率,应该在char型数据之后,存放长度较小的成员。即在定义结构体时,应该按照长度递增的顺序依次定义各个成员。优化后的实例代码为

    #pragma pack(4)
    struct TEST
    {
        char e;         //1
        char c[3];      //3
        short b;        //2
        long a;         //4
        float d;        //4
        double f;       //8
    }test;

    运行测试程序,输出结果为
    这里写图片描述
    可见,通过调整结构体的成员顺序,达到了优化内存的目的。各个成员变量在内存中的分布图为
    这里写图片描述

    结构体只浪费了2个字节的空间,内存使用率达到92%。显然通过优化结构体成员的定义顺序,在同样满足内存对齐的要求下,可以大大减小内存的浪费。

    展开全文
  • 我有4个unsigned int数组,其中每个元素必须在内存对齐,以使其(hex)地址以零结尾.例如.int main(){size_t i;static unsigned int a[2] __attribute__ ((aligned (16)));static unsigned int b[2] __attribute...

    我无法在Cell处理器上调整DMA传输的内存.我需要地址的最后4位为0.

    我有4个unsigned int数组,其中每个元素必须在内存中对齐,以使其(hex)地址以零结尾.

    例如.

    int main()

    {

    size_t i;

    static unsigned int a[2] __attribute__ ((aligned (16)));

    static unsigned int b[2] __attribute__ ((aligned (16)));

    static unsigned int c[2] __attribute__ ((aligned (16)));

    static unsigned int d[2] __attribute__ ((aligned (16)));

    for (i = 0; i < 2; ++i) {

    printf("a[%u] = %p\n", &a[i]);

    printf("b[%u] = %p\n", &b[i]);

    printf("c[%u] = %p\n", &c[i]);

    printf("d[%u] = %p\n", &d[i]);

    }

    return 0;

    }

    输出:

    a[0] = 0x10010b60

    b[0] = 0x10010b50

    c[0] = 0x10010b40

    d[0] = 0x10010b30

    a[1] = 0x10010b64

    b[1] = 0x10010b54

    c[1] = 0x10010b44

    d[1] = 0x10010b34

    这里的问题是每个数组的第二个元素似乎不是16位对齐的(它们的地址’以4结尾).

    我需要地址看起来像这样:

    a[0] = 0xXXXXXXX0

    b[0] = 0xXXXXXXX0

    c[0] = 0xXXXXXXX0

    d[0] = 0xXXXXXXX0

    a[1] = 0xXXXXXXX0

    b[1] = 0xXXXXXXX0

    c[1] = 0xXXXXXXX0

    d[1] = 0xXXXXXXX0

    展开全文
  •  0 约定和预备知识 0.1 地址边界 如果把字节看作小房子,内存就是顺序排列的小房子。每个小房子都有一个顺序编号的门牌号码,例如:0,1,2,...,0xffffffff。我们 把这个门牌号码称作地址。本文将2的整数倍的地址记...
  • 最近闲来无事,翻阅msdn,在预编译指令中,翻阅到#pragma pack这个预处理指令,这个预处理指令为结构体内存对齐指令,偶然发现还有另外的内存对齐指令aligns(C++11),__declspec(align(#))(Microsoft专用),遂去探究...
  • 详解内存对齐

    千次阅读 多人点赞 2021-08-17 01:00:22
    结构体的内存对齐规则 一提到内存对齐,大家都喜欢拿结构体的内存对齐来举例子,这里要提醒大家一下,不要混淆了一个概念,其他类型也都是要内存对齐的,只不过拿结构体来举例子能更好的理解内存对齐,并且结构体中...
  • 内存对齐,memory alignment.为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。内存对齐...
  • C++: 内存对齐

    2022-07-28 11:28:08
    C++: 内存对齐
  • #pragma pack() :取消内存对齐访问 #pragma pack(n) (n=1/2/4/8):按n字节对齐 #pragma pack(2) struct mystruct1 { int a; char b; short c; } struct mystruct2 { int a;; double b; short c; } ...
  • 内存对齐,memory alignment.为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。  内存...
  • 内存对齐的初步讲解 内存对齐可以用一句话来概括: “数据项只能存储在地址是数据项大小的整数倍的内存位置上” 例如int类型占用4个字节,地址只能在0,4,8等位置上。 例1: 代码如下:#include <stdio>struct xx{ ...
  • C++中的内存对齐实例详解 内存对齐  在我们的程序中,数据结构还有变量等等都需要占有内存,在很多系统中,它都要求内存分配的时候要对齐,这样做的好处就是可以提高访问内存的速度。 我们还是先来看一段简单的...
  • 内存对齐意味将数据类型写入到内存地址时是按照它们大小切割的,内存对齐会带来性能提升,是Java性能提升的黑技术。内存对齐定义(n是2的乘幂):boolean nAligned = (address%n) == 0;如果内存地址是n字节的倍数,...
  • 深入内存对齐的详解

    2020-12-31 09:44:49
     例如,下面的结构各成员空间分配情况(假设对齐方式大于2字节,即#pragma pack(n), n = 2,4,8…下文将讨论#pragmapack()): 代码如下:struct test { char x1; short x2; float x3; char x4;}; 结构的第一个成员...
  • 但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐对齐的作用和原因:各个硬件平台对存储空间的处理...
  • 内存对齐详解

    2019-01-13 17:31:45
    详细解读内存对齐原则,通过实例让你完全掌握内存对齐
  • 内存对齐3.1 结构体成员默认内存对齐3.2 不同架构内存对齐方式3.3 小试牛刀3.3.1 前置填充3.3.2 中间填充3.3.3 尾随填充 1. 同个结构体占用内存可变化      在 C语言之结构体 章节里,对struct的功能和使用进行...
  • 定义结构体我没有注意到数据对齐,因为在底层实现中,我传入的数据buffer是排列整齐的,而强制转化的结构体格式中,我定义的时候没有使用__attribute__((__packed__))或者__packed强制数据对齐,导致结构体成员真实...
  • 内存对齐内存对齐规则解释、内存对齐原理

    千次阅读 多人点赞 2020-03-28 23:44:31
    一、内存对齐的原因 我们都知道计算机是以字节(Byte)为单位划分的,理论上来说CPU是可以访问任一编号的字节数据的,我们又知道CPU的寻址其实是通过地址总线来访问内存的,CPU又分为32位和64位,在32位的CPU一次...
  • 什么是内存对齐?为什么要内存对齐

    万次阅读 多人点赞 2018-08-06 11:47:01
    要了解为什么要内存对齐,首先我们要了解什么是内存对齐 什么是内存对齐 关于什么是内存对齐,我们先来看几个例子 typedef struct { int a; double b; short c; }A; typedef struct { int a; short b; ...
  • 结构体内存对齐

    千次阅读 多人点赞 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++内存对齐

    千次阅读 2021-12-29 20:09:19
    这里写目录标题空类/静态成员内置类型数据成员结构体数据成员虚函数继承内存对齐的意义 内存对齐的基本原则: 结构(struct/class)的内置类型数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的...
  • C++ 内存对齐原则及作用 C++ 内存对齐原则及作用 C++ 内存对齐原则及作用
  • 内存分配
  • 在64位机器上,依然按照32位来进行内存对齐。 package main import ( "fmt" "unsafe" ) type demo1 struct { a int8 b int16 c int32 } type demo2 struct { a int8 c int32 b int16 } type demo3 ...
  • 为什么要进行结构体内存对齐

    千次阅读 多人点赞 2018-08-10 21:59:12
    结构体内存对齐 什么是结构体内存对齐 结构体不像数组,结构体中可以存放不同类型的数据,它的大小也不是简单的各个数据成员大小之和,限于读取内存的要求,而是每个成员在内存中的存储都要按照一定偏移量来存储...
  • 一.背景:1.使用#pragma定义结构体:RECV_CMD_DATA_t和RECV_CMD_PACK_t,按照1字节进行内存对齐#pragma pack(1) typedef struct recv_cmd_data { int iType; long long llInt; int iLen; ...
  • 为了优化CPU访问和优化内存,减少内存碎片,编译器对内存对齐制定了一些规则。但是,不同的编译器可能有不同的实现,本文只针对VC++编译器,这里使用的IDE是VS2012。 #pragma pack()是一个预处理,表示内存对齐。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 181,538
精华内容 72,615
关键字:

内存对齐方式