C++之数据对齐

本文深入探讨了数据对齐的基本概念,包括自身对齐值、指定对齐值与有效对齐值等,并通过实例说明如何应用这些概念来提高CPU读取数据的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CPU在读取数据时会一次读取好几个字节,比如第一次读取0x00~0x03四个字节处理,第二次读取0x04~0x07四个字节处理,而不巧的是一个int型数据刚好存储于0x02~0x05这一片连续区域,那么为了读取这个int数据,CPU不得不读取两次内存再分别取高低字节进行拼凑才能够得到该数据,效率很低。

所以引入了数据对齐这么一个办法,首先了解一下自身对齐值、指定对齐指、有效对齐值的概念。

1. 基本数据类型的自身对齐值:就是对基本数据类型sizeof()后得到的值,记住:char-1Byte,short-2Byte,int-4Byte,float-4Byte,long-4Byte,long long-8Byte,double-8Byte。

2.结构体或者类的自身对齐值:就是其数据成员中sizeof()最大那个的值。

3.数组的自身对齐值:数组元素类型的大小,eg: int a[20]; a的自身对齐值为4Byte。

4.指定对齐值:#pragma pack (value),其中value的值就是指定的对齐值大小。

5.有效对齐值:将自身对齐值与指定对齐值进行比较后,较小的那个即为有效对齐值。

注意:有效对齐值才是我们在数据对齐时要使用的,自身对齐值及指定对期指的作用仅仅是比较得到有效对齐值。有效对齐值N表示该数据的存储起始地址%N=0。

再来了解数据对齐的基本规则:

1.数据或结构体、类中的数据成员的存储起始地址为有效对齐值N的倍数。

2.结构体或类或联合体最终的大小应为有效对齐值N的倍数(圆整)。

最后贴1个程序供自己实战一下,这个程序来自博客http://www.cnblogs.com/bakari/archive/2012/08/27/2658956.html

struct Practice2
{
  struct T1
  {
    char _cA;
    int _iB;
    float _fC;
   } _objX;
  int _iD;
  char _iE;
};

1、 求出此结构体在默认情况下的大小,并将其内存布局通过图文并茂的方式描述清楚。

2、 若在此结构体上之前加入#pragma pack(4),之后加上#pragma pack(),那么此时,其大小又为多少?

解:(1)0x00~0x11存T1,0x12~0x15存_iD,0x16存_iE,0x17~0x19位packing(圆整)。占20字节

       (2)0x00~0x11存T1,0x12~0x15存_iD,0x16存_iE,0x17~0x19位packing(圆整)。占20字节

好像是一样的答案,哈哈~~偷笑完结撒花。。

### C++ 中的数据对齐概念 在 C++ 编程语言中,数据对齐是指编译器为了提高访问速度而按照特定规则安排对象在内存中的位置。对于不同类型的变量,编译器会根据其自然边界来决定如何放置这些变量,从而使得 CPU 可以更高效地读取和写入数据。 ### 数据对齐的规则 当定义一个结构体或者类时,其中成员变量之间的排列并非简单地按声明顺序连续占用内存空间;相反,由于存在字节填充现象,实际使用的总大小可能会大于各个字段所需的空间之和。具体来说: - **最大成员对齐值**:结构体内最大的基本类型决定了该结构的整体对齐方式。例如,在给定的例子 `class A` 中含有 `_a(double)` 和静态成员 `_b(int)` ,因为 double 类型通常需要 8 字节对齐[^1]。 - **成员间对齐调整**:如果当前偏移量不是下一个待加入元素所需的最小对齐单位,则会在两者之间插入适当数量的未命名位域(即所谓的“空洞”),直到满足条件为止。 - **整体尺寸扩展至最严格对齐倍数**:最终计算出来的结构体或类实例所占的实际字节数目会被向上舍入到等于或超过所有内部组件中最严格的那个对齐需求的一个整数值上。 ```cpp #include <iostream> using namespace std; class A { public: void Print() { cout << "Print()" << endl; } private: double _a; static int _b; }; int main() { cout << sizeof(A) << endl; // 输出结果为 8 return 0; } ``` 上述代码展示了类 `A` 的布局情况。这里需要注意的是,尽管有一个静态成员 `_b` 存在于类定义里,但它并不会影响单个对象占据多少内存,因为它只有一份副本存放在全局区域而非每个实例之中。 ### 如何控制数据对齐行为 有时开发者可能希望改变默认的行为模式,这时可以利用一些预处理器指令或是属性来进行自定义设置: - 使用 `#pragma pack(n)` 来指定新的打包级别 n (n=1,2,4,8 或者 16),这会影响之后遇到的所有结构体/联合体直至遇见另一个同名命令恢复原状; - 应用 GNU 扩展关键字 `__attribute__((aligned(N)))` 给某个特定类型加上额外约束 N 表示期望达到至少多宽的边界; - Microsoft Visual Studio 提供了类似的特性通过附加说明符 `[align(value)]` 完成相似功能。 以上手段允许程序员更加灵活地管理程序内的资源分布状况,特别是在嵌入式开发领域显得尤为重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值