C\C++中结构体-字节对齐

文章介绍了内存对齐的概念,以64位程序中的结构体为例,说明内存对齐规则是如何影响结构体大小的。通过分析不同成员顺序下的内存布局,强调了按照数据类型从小到大排列可以节省内存空间,并指出最长基本数据类型为对齐单位,总大小需为该单位的倍数。

假设结构体如下:(64bit程序中实例)

struct {
  char c;   //1*8
  double d; //8*2
  int i;    //4*5
  long l;   //4*6
} s;

首先各基本数据类型所占字节为:char(1)、double(8)、int(4)、long(4)

  1. 先查找结构体中最长的字节为对齐长度,这里是double(8)

  2. 那么按照顺序c(char)先进内存此时内存结构:

c
  1. 然后就是填入d(double),因为数据类型都是整数倍,第一行的8个内存已经被占用了一个,那就只能从第二行开始填入内存;剩余第一行的内存做对齐处理。此时内存如下:
c*******
dddddddd
  1. 填入i(int),此时内存空间前16个字节被占用,内存如下:
c*******
dddddddd
iiii
  1. 再填入l(long),可以看到第三行刚好可以填入4个字节(long),那么就不需要填入对齐字符。
c*******
dddddddd
iiiillll

最终结构体长度就是24byte

再修改一下结构体的成员如下:

struct {
  char c;   //1*8
  double d; //8*2
  int i;    //4*5
  double d2; //新增成员
  long l;   //4*6
} s;

那么此时的内存结构图:

c*******
dddddddd
iiii****
d2d2d2d2d2d2d2d2
llll****

此时大小为:40byte

总结:
  1. 内存对齐是以内存占用最长的基本数据类型作为对齐单位的,且对齐后的总大小是最长字节的倍数。

  2. 数据结构的各类型数据的顺序也会影响内存占用大小,所以一般顺序都是从小->大的顺序进行结构体成员添加,这样就可以节省内存空间了。(相邻的成员类型占用长度不要多大,如(char -> double就浪费了7个字节))

C++中定义结构体时,字节对齐的处理主要依赖于编译器的默认行为以及开发者通过特定指令进行的调整。结构体字节对齐是为了提高CPU访问内存的效率,确保数据成员存储在合适的地址边界上,从而避免因访问未对齐数据而导致性能下降或运行时错误。 ### 结构体字节对齐的基本规则 1. **默认对齐方式**:通常情况下,编译器会根据结构体中最大成员的大小来决定整个结构体对齐方式。例如,在32位系统中,如果结构体包含一个`int`(4字节)、一个`char`(1字节一个`short`(2字节),那么整个结构体将以4字节为单位进行对齐。每个成员的起始地址必须是其自身大小的整数倍[^3]。 2. **结构体总大小的调整**:结构体的总大小必须是其最大成员对齐大小的整数倍。如果计算出来的大小不满足这一条件,则会在结构体末尾自动填充额外的字节以满足对齐要求。例如,若结构体的实际大小为9字节,而最大成员的对齐大小为4字节,则结构体的最终大小将被调整为12字节[^3]。 3. **嵌套结构体对齐**:如果结构体中包含另一个结构体作为成员,那么该嵌套结构体的起始地址必须是其内部最大成员对齐大小的整数倍。例如,如果嵌套结构体内部有`char`、`int``double`等成员,则嵌套结构体应从8字节的整数倍地址开始存储[^4]。 ### 自定义字节对齐方式 除了使用编译器的默认对齐方式外,还可以通过预处理指令`#pragma pack`来显式指定结构体对齐方式。该指令允许开发者设置结构体中各成员之间的对齐粒度,从而控制结构体内存布局。 - **设置对齐方式**:可以使用`#pragma pack(n)`来指定结构体成员按照`n`字节对齐。例如,`#pragma pack(2)`表示结构体成员将按照2字节对齐。此时,结构体中每个成员的起始地址必须是其自身大小与`n`中的较小值的整数倍。例如,对于以下结构体定义: ```cpp #pragma pack(2) struct C { char b; int a; short c; }; #pragma pack() ``` 在此设置下,`char b`占用1字节,`int a`占用4字节但必须从2字节的整数倍地址开始,因此`b`之后会有一个填充字节,使得`a`从地址2开始;`short c`占用2字节,必须从2字节的整数倍地址开始,因此`a`之后不需要填充,`c`直接紧随其后[^2]。 - **恢复默认对齐**:使用`#pragma pack()`可以恢复编译器的默认对齐方式。这通常用于在代码中临时更改对齐设置后,确保后续的结构体定义不受影响。 ### 紧凑排列结构体 有时,开发者可能希望结构体尽可能紧凑地排列,以减少内存占用。在这种情况下,可以使用`__attribute__((packed))`属性来取消编译器的自动对齐优化。例如: ```cpp struct test2 { char c; int i; } __attribute__((packed)); ``` 在这种情况下,结构体中的成员将按照它们的实际大小连续存储,而不进行任何填充。例如,上述`test2`结构体的大小将是`char`(1字节)加上`int`(4字节),总共5字节,而不是默认对齐方式下的8字节[^1]。 ### 总结 在C++中定义结构体时,字节对齐可以通过编译器的默认行为或显式的对齐指令来控制。开发者可以根据具体需求选择是否使用默认对齐、自定义对齐或紧凑排列,以优化内存使用或提高性能。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值