结构体字节对齐问题

结构体(struct)的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。先看下面定义的两个结构体.
struct
{
  char a;
  short b;
  char c;
}S1;
struct
{
 char  a;
 char  b;
 short c;
}S2;

分别用程序测试得出sizeof(S1)=6 , sizeof(S2)=4

可见,虽然两个结构体所含的元素相同,但因为其中存放的元素类型顺序不一样,所占字节也出现差异。这就是字节对齐原因。通过字节对齐,有助于加快计算机的取数速度,否则就得多花指令周期。

字节对齐原则

结构体默认的字节对齐一般满足三个准则:

1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

通过这三个原则,就不难理解上面两个struct的差异了.

对于struct S1, 为了使short变量满足字节对其准则(2), 即其存储位置相对于结构体首地址的offset是自身大小(short占2个字节)的整数倍,必须在字节a后面填充一个字节以对齐;再由准则(3),为了 满足结构体总大小为short大小的整数倍,必须再在c后面填充一个字节。

对于struct S2, 却不必如上所述的填充字节,因为其直接顺序存储已经满足了对齐准则。

如果将上面两个结构体中的short都改为int(占4个字节), 那么会怎么样呢? 程序得出sizeof(S1)=12, sizeof(S2)=8
利用上面的准则,也不难计算得出这样的结果。S1中在a后面填充3个字节、在c后面填充3个字节,这样一共12个字节;S2中在a、b顺序存储之后填充两个字节用以对其,这样一共就8个字节。

当然,在某些时候也可以设置字节对齐方式。这就需要使用 #pragma pack 。
#pragma pack(push) //压栈保存
#pragma pack(1)// 设置1字节对齐
struct
{
  char a;
  short b;
  char c;
}S1;
#pragma pack(pop) // 恢复先前设置

如上所示,将对其方式设为1字节对齐,那么S1就不填充字节,sizeof为各元素所占字节之和即4。这一点在从外部2进制文件中读入struct大小的数据到struct中,是很有用的.

此外,对于空结构体(即内部没有任何元素),在UNIX平台gcc4.1下的sizeof 为0,而在Windows平台VC6下得出的sizeof却为1!我也不知道怎么回事,真是个有趣的现象!

 
### 结构体字节对齐原理 在C/C++编程中,结构体内存布局遵循特定的字节对齐规则。这些规则旨在提高访问速度并确保数据一致性。具体来说: - **对齐基本原则**:为了优化CPU读取效率,编译器会根据目标平台的要求,在必要时向结构体成员间插入填充字节[^2]。 #### 成员排列与填充机制 当定义如下所示的一个简单结构体`D`: ```cpp struct D { char a; double b; }; ``` 如果不对该结构体施加任何特殊的对齐约束,则默认情况下它将依据最宽基本类型的边界来调整内部元素的位置关系——即8字节(对于大多数现代架构而言),这意味着即使第一个字符型字段仅占用单个字节空间,紧随其后的双精度浮点数也会被放置在一个新的、可以被8整除的地址上,从而使得整个对象占据至少16个连续存储单元[^1]。 然而,通过指定`.align=1`属性或利用预处理指令如`#pragma pack(push, 1)`可改变这一行为模式,强制所有组件紧密相邻而不留额外间隔,进而减少整体尺寸至最小化状态9字节[^4]。 ### 解决方案实例分析 考虑另一个例子中的测试用结构体`test`: ```cpp struct test { char x1; // 1 byte short x2; // 2 bytes float x3; // 4 bytes char x4; // 1 byte }; ``` 如果不做特殊处理,默认情况下各组成部分之间的相对位置可能会因为自动添加的垫片而发生变化,最终导致实际分配给此类实体的空间超过预期值12字节。为了避免这种情况发生,并确保跨不同环境下的兼容性良好,可以在源文件顶部加入适当配置语句以显式控制打包策略[^3]: ```cpp #pragma pack(push, 1) // 开始应用紧凑模式 // ... 定义受影响的数据类型 ... #pragma pack(pop) // 恢复原有设定 ``` 这样做不仅有助于节省资源消耗,还能有效防止因端到端通信过程中可能出现的信息失真现象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值