一、为什么要进行字节对齐?
简单来说就是提高cpu对内存的访问效率。为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
不同的平台(cpu)和编译器对字节对齐的处理是不一样的,但是原理上大同小异。
一般来说是不需要太过关注字节对齐的,因为编译器会自动帮助我们完成。但是某些时候,字节对齐可能是非常隐蔽的bug的诱因。所以,了解其规则是有必要的。
二、基本原则:
对齐值:一个变量的对齐值取的是自身长度大小和通过#pragma pack(n)指定的对齐值(没有指定的话,默认为8)中较小的
圆整值:编译器会对结构体进行圆整(即,在结构体最末填充一定字节),圆整值的大小(也可以简单理解为结构体最后一个变量将占用的大小)取的是结构体中最宽的基本类型和通过#pragma pack(n)指定的对齐值中较小的
1) 结构体的首地址能够被其最宽基本类型成员长度和通过#pragma pack(n)指定的对齐值之间较小的值所整除;
2) 结构体每个成员相对于结构体首地址的偏移量都是其对齐值的整数倍,如有需要编译器会在成员之间加上填充字节;
3) 结构体的总大小为结构体圆整值的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
三、实例分析:
a、基本对齐例子
1、struct Test1 {
char a;
int i;
char c;
};
sizeof(Test1) = 12
分析:变量i会进行字节对齐,对齐值为4,编译器会在a和i之间填充3字节。最后编译器会对结构体进行圆整,在结构体最后填充3字节(因为结构体中最大的基本类型为int,长度为4字节)。
2、上例中,如果加上 #pragma pack(2)
则,sizeof(Test1) = 8
分析:同样成员变量i会进行字节对齐,但是由于指定的对齐长度为2,并且比int类型长度4要小,所以对齐值为2。由于指定了对齐值2,所以变量c后会再填充1字节,以进行圆整。
如果c的类型为short,则sizeof(Test1) = 8, 因为short的长度为2,不需要再进行圆整。
如果c的类型为int ,则sizeof(Test1) = 10,同样不需要进行圆整,总大小=2+4+4
3、上例中,如果加上 #pragma pack(8) 或 如果加上 #pragma pack(4), 则,依然 sizeof(Test1) = 12
b、另外一个例子
1、struct Test2 {
char a;
double d;
int i;
};
分析: sizeof(Test2) = 24 = 8 + 8 + 8 对齐值=8,圆整值=8,所以变量a后会填充7字节,变量i后会填充4字节
如果加上 #pragma pack(8),结果也是一样的。
如果加上 #pragma pack(4),则 sizeof(Test2) = 16 = 4 + 8 + 4
c、结构体之间的对齐
1、 struct Test3 {
Test1 t1;
Test2 t2;
};
sizeof(Test3) = 40
分析: sizeof(Test1) = 4 + 4 + 4 = 12 sizeof(Test2) = 8 + 8 + 8 = 24
由于原则1,Test2的最宽基本类型为double,长度为8,则Test2的首地址应该能被8整除。所以在Test1和Test2之间被填充了4字节。注意,这里看的是基本类型的宽度而不是结构体的总长度,即便Test1或Test2中再嵌套结构体或包含数组,最终看的也只是其中的一个基本类型。
2、如果加上 #pragma pack(4),则 sizeof(Test3) =28
分析:sizefo(Test1) = 4 + 4 + 4 = 12 sizeof(Test2) = 4 + 8 + 4 = 16
由于指定了对齐值4,再看原则1时,Test2的首地址应该能被4整除(因为指定对齐值4小于最宽基本类型8)。所以结构体之间不需要再填充字节。
d、枚举间的对齐
1、union u1 {
int i;
char c;
};
union u2 {
Test1 t1;
double d;
};
struct Test4 {
u1 uu1;
u2 uu2;
};
sizeof(u1) = 4
sizeof(u2) = 16
sizeof(Test4) = 24
分析:Test1的大小为12,但是由于u2中的最宽基本类型double为8,所以最后u2实际的圆整大小为8字节,故虽然Test1的大小为12,但是u2联合体所占用的内存空间并不仅仅是联合体中最长的成员,而是圆整后的16字节;
同样,u2联合体的首地址也应该是8的倍数,而不是看Test1的大小,故uu1和uu2之间会再被填充4字节,所以Test4的大小为24
四、总结
通过之前的例子和分析可见,只要掌握了字节对齐的原则,万变不离其宗。简单总结一下就是:一个变量的对齐看的是自身长度和指定对齐值之间较小的;结构体的对齐(包括头和尾)看的是结构体中最大基本类型的长度和指定对齐值之间较小的。
分享到:
相关推荐
本文将围绕“VS C++字节对齐方式”这一主题展开讨论,通过对示例代码的分析来探讨Visual Studio环境下C++语言如何处理字节对齐问题,以及程序员应如何合理利用编译器特性来优化代码性能。 #### 二、字节对齐的基本...
理解C++中的字节对齐机制对于优化内存使用和提升程序性能至关重要。通过合理地安排结构体成员变量的顺序,开发者可以在不影响程序功能的前提下减少不必要的填充字节,节省内存资源。此外,掌握不同平台的对齐要求有...
字节对齐是一种编程策略,主要应用于C语言和C++中,目的是为了提高程序执行的效率和内存访问的性能。当结构体中的成员变量在内存中存储时,编译器会根据成员变量的类型和系统架构自动进行字节对齐,确保每个变量都能...
这可能是项目的一个归档,包含有与字节对齐相关的源代码、文档或者日志,记录了2013年12月31日关于字节对齐调整的具体内容。通过分析这个文件,我们可以深入理解当时的改动,比如查看是否涉及到结构体的字节对齐设置...
字节对齐是一种在计算机编程中,特别是在C/C++编程中常见的优化策略,它涉及到如何在内存中组织数据,以确保高效访问和避免硬件错误。字节对齐的基本原理是根据数据类型及其大小来确定它们在内存中的起始位置,以...
**系统级编程:字节对齐的理解与实践** 在计算机科学中,系统级编程涉及到操作系统、硬件交互以及底层数据处理等方面。在这个过程中,一个至关重要的概念是“字节对齐”,它直接影响到程序的性能、内存利用率以及...
标题中的"pack 字节对齐"是指在编程中,尤其是使用C++时,关于数据结构内存布局的一个关键概念。字节对齐是指编译器在安排数据结构成员时,会按照特定的规则来调整成员的位置,使其地址能够满足某种对齐要求。这种...
1. **编译器默认对齐规则**:大多数编译器都有默认的对齐规则,如Visual C++默认采用4字节对齐。 2. **使用`#pragma pack`指令**:这是改变结构体中成员对齐方式最常用的方法之一。例如,在代码示例中通过`#pragma ...
通过阅读"字节对齐你该知道的事情.docx"和"070331233044[1].pdf"这两份文档,你可以深入理解字节对齐的细节,包括具体实现、对性能的影响以及如何在实际编程中应用这些知识。文档中可能还涵盖了如何调试和解决因字节...
通过分析提供的代码示例及其描述,我们可以深入了解字节对齐(Byte Alignment)这一概念,并探讨其在不同编译器设置下对结构体内存布局的影响。 ### 字节对齐概述 字节对齐是指数据在存储时按照某种特定的单位进行...
这些规则通常与硬件平台有关,比如32位系统通常采用4字节对齐,64位系统可能采用8字节对齐。对齐的主要目的是提高数据存取速度,减少不必要的内存访问,并确保硬件能够高效地处理数据。 结构体是C/C++等编程语言...
### C++内存对齐原理与实践 #### 一、引言 C++作为一种高效且功能强大的编程语言,在处理数据时需要特别关注内存管理问题。内存对齐是C++中的一个重要概念,它涉及到如何在内存中排列数据以提高程序的执行效率。...
为了更好地理解字节对齐的具体实现,我们可以利用`offsetof`宏来检查结构体中各成员的偏移量。 ##### offsetof宏的使用 `offsetof`宏是标准C库的一部分,用于计算结构体或联合体中每个成员相对于结构体起点的偏移...
例如,#pragma pack(2)将结构体的对齐规则设置为2字节对齐,而#pragma pack(4)将结构体的对齐规则设置为4字节对齐。 六、结论 C++内存对齐是为了提高存取效率和避免硬件平台相关的错误的一种机制。VC对结构体的...
修改对齐值为 1:#progma pack (1) /*指定按 1 字节对齐*/ struct D { char b; int a; short c; }; #progma pack () /*取消指定对齐,恢复缺省对齐*/ sizeof(struct D)值为 7。 C++ 中的内存对齐规则是为了提高程序...
以下是两个容易被忽视的C++字节对齐问题: 首先,让我们讨论联合体(Union)的字节对齐。联合体是一种特殊的结构体,其中的所有成员共享相同的内存空间。在上述例子中,我们有一个名为`com`的结构体,它包含一个...
### C++内存对齐原理与实践 #### 一、引言 在C++编程中,内存对齐(Memory Alignment)是一项重要的技术,它涉及到如何在内存中存储数据以提高程序的运行效率。良好的内存对齐不仅可以减少数据访问的时间,还可以...