美文网首页C++
c++内存对齐

c++内存对齐

作者: 王王王王王景 | 来源:发表于2019-07-13 17:11 被阅读36次

1、为什么要进行内存对齐呢?

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

为什么内存未对齐需要两次访问内存?

假设操作系统每次在内存中每次要取四个字节的数据,如果需要将黄色部分取出,则需要取两次;第一次取03的数据,第二次取47的数据;

// 各个数据在未对齐的情况下
struct data1 {
  char a; // 0
  char b; // 1
  int c; // 2~5
}

如果进行了内存对齐,则数据存储如下图所示:



数据相对于起始点的偏移地址都是能整除对齐数的,因此只需要取一次数据即可

编译器一般按照几个字节对齐呢?本文中两个编译器默认按照类中最大类型长度来对齐,我么也可以使用语句#pragma pack(i)(i = 1,2,4,8,16)来设置对齐字节数目,vs还可以在项目属性-配置属性-c/c++-代码生成-结构成员对齐设置。

2、内存对齐的原则

对于结构体变量内存对齐遵循以下三个原则

  1. 变量起始地址能够被其对齐值整除,结构体变量的对齐值为最宽的成员大小。
  2. 结构体每个成员相对于起始地址的偏移能够被其自身对齐值整除,如果不能则在前一个成员后面补充字节。
  3. 结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节。

此外还有编译器的默认对齐值,一般默认对齐值为4(结构体的实际对齐值会取结构体对齐值和编译器默认对齐值中较小的那一个)。

struct Test
{
    char a;
    int b;
    short c;
};

分析:

第一位char a相互对于开始的偏移值是0,满足原则1,后面的int b的的偏移地址不满足(偏移地址需要能够整除自身的对齐值),因此需要在a后面进行填充3个字节,此时c的偏移地址是满足的要求的,为了满足原则3,需要在c后面添加两个字节的的空间,所以整体的大小是12;

C++中可以使用alignof获取类型的对齐值,char类型的对齐值为1, int的对齐值为4, short的对齐值为2,整个结构体的对齐值为4。假设结构体变量的起始地址已经对齐,那么结构体的第一个成员a已经对齐,由于第一个成员a的大小为1而第二成员b的对齐值为4,则根据第二条对齐原则需要在第一个成员后填充3个字节才能使第二个成员对齐,第二个成员对齐后第三个成员的起始地址刚好为其对齐值的整数倍所以不需要进行填充,此时算上填充字节,结构体占用的总字节为10字节,又由第三条原则,结构体大小需要为4的整数倍,因此需要在第三个成员c后填充2个字节,可以算得结构体的总大小为12(在默认对齐值为2时,大小为8字节)。

改变结构体成员顺序如下:

struct Test
{
    int b;
    short c;
    char a;
};

改变成员顺序后,若结构体变量的起始地址已经对齐,则根据原则2三个成员均以对齐(c的偏移地址是4,4mod2 = 0;a的偏移地址是6 6mod1 = 0),中间不需要进行填充,此时结构体占用的总字节为7,又由原则3需要在最后一个变量后填充1个字节,因此结构体总大小为8(在默认对齐值为2时,大小也为8字节)。

从上面的例子可以看出根据对齐原则合理安排结构体成员的顺序可以减少内存的占用。


#include<iostream>
using namespace std;
 
#pragma pack(4) // 将内存对齐值指定为4个字节
#pragma pack(2) // 将内存对齐值指定为2个字节
struct m   
{
    int a;  
    short b;
    int c;
};
int main()
{
    cout <<"结构体m的大小:"<< sizeof(m) << endl;
    cout << endl;
    int offset_b = offsetof(struct m, a);// 获得成员a相对于m储存地址的偏移量
    cout <<"a相对于m储存地址的偏移量:"<< offset_b << endl;
    system("pause");
    return 0;
}

输出:
将内存对齐值指定为4个字节的时候 结构体的大小为 12
将内存对齐值指定为2个字节的时候 结构体的大小为 10
如果不进行指定每一种类型的对齐值,有默认的

相关文章

  • golang 和 C++ 的内存对齐

    golang 和 C++的内存对齐,基本一致,记住规则和对应类型的 size 即可 内存对齐规则 有效对齐值是固定...

  • sizeof与字节对齐

    参考 【面试题】sizeof引发的血案编译器与字节对齐c 语言字节对齐问题详解C/C++内存对齐内存存取粒度C和C...

  • c++内存对齐

    1、为什么要进行内存对齐呢? 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台...

  • sse中内存对齐问题

    c++ sse中无论声明栈内存还是堆内存都需要声明内存对齐,在VC++中:堆内存分配使用_aligned_mall...

  • 2.iOS底层学习之内存对齐

    学习了内存对齐之后的疑问?? 1.为啥要内存对齐?2.内存对齐的规则?3.内存对齐实例分析。 内存对齐的目的 上网...

  • 内存对齐

    本次主要讨论三个问题: 什么是内存对齐 内存对齐的好处 如何对齐 内存对齐 内存对齐是一种提高内存访问速度的策略。...

  • 关于C++内存对齐

    关于C++内存对齐 测试代码如下: instance 的地址为0X0015FE44,如下图所示 在内存中找到该地址...

  • c++内存对齐--GeekBand

    c++中每个class包含两部分:数据和函数。对每个对象来说函数部分大家公用一份,而数据部分每个对象是独立的。所以...

  • C++之内存对齐

    什么是内存对齐 编译器为每个“数据单元”按排在某个合适的位置上。 C、C++语言非常灵活,它允许你干涉“内...

  • C/C++内存对齐

    在面试或工作中,经常会遇到内存对齐的问题。这里结合我的理解谈一谈对内存对齐的理解。 1. 为什么要内存对齐,不对齐...

网友评论

    本文标题:c++内存对齐

    本文链接:https://www.haomeiwen.com/subject/crjmkctx.html