第1章:数据类型与字节对齐——跨平台的第一道坎
说实话,我刚开始做跨平台开发时,最头疼的就是数据类型。你以为int就是4个字节?太天真了。我在嵌入式平台和PC之间传数据,结果结构体对不上,程序直接崩溃。嗯,今天我们就来聊聊这个坑。
1.1 基本数据类型的大小——sizeof陷阱
先看个简单的例子。你在Windows上写代码,int是4字节。换到某些嵌入式平台,int可能变成2字节。为什么会这样?因为C语言标准只规定了最小范围,没规定具体大小。
// 你以为的:
printf("int size: %zu\n", sizeof(int)); // 4
// 实际在不同平台:
// Windows/Linux x86_64: 4
// 某些嵌入式MCU: 2
// DSP平台: 有时是4,有时是2
我个人习惯,写跨平台代码时,永远不用int、long这种模糊类型。用
核心原则:跨平台代码中,永远使用
| 类型 | 大小(字节) | 跨平台建议 |
|---|---|---|
| char | 1 | 可用,但注意signed/unsigned |
| int | 2或4 | ❌ 避免使用 |
| long | 4或8 | ❌ 避免使用 |
| int32_t | 4 | ✅ 推荐使用 |
| uint64_t | 8 | ✅ 推荐使用 |
我在项目中遇到过一个问题:用long存时间戳,在32位平台是4字节,到64位平台变成8字节。结果序列化后的数据,两边解析完全对不上。从那以后,我所有跨平台数据交换,一律用int64_t。
1.2 字节对齐——结构体的隐藏尺寸
你想想看,一个结构体里定义了3个字段,sizeof算出来却比字段大小之和还大。这就是字节对齐在搞鬼。
struct Example {
char a; // 1字节
int b; // 4字节
short c; // 2字节
};
// 你以为:1 + 4 + 2 = 7字节
// 实际:12字节(对齐后)
为什么会这样?因为CPU读取内存时,按字长对齐效率最高。编译器会在字段之间插入填充字节。默认对齐规则是:每个字段的起始地址,必须是其大小的整数倍。
注意:不同平台的对齐规则可能不同。ARM平台和x86平台的对齐策略就有差异。我曾经在ARM上调试一个网络协议栈,结构体大小和PC端差了4个字节,排查了整整一天。
1.3 #pragma pack——手动控制对齐
当你需要精确控制结构体大小时,可以用#pragma pack。比如你要和硬件寄存器交互,或者做网络协议解析,对齐必须和对方一致。
#pragma pack(push, 1) // 按1字节对齐
struct PackedExample {
char a;
int b;
short c;
};
#pragma pack(pop)
// 现在sizeof(PackedExample) = 7
// 没有填充字节,紧凑排列
我建议,使用#pragma pack时要注意几点:
- 只在需要精确控制的地方使用,不要全局设置
- 用push/pop成对使用,避免影响其他代码
- 对齐后的结构体访问速度会变慢,这是性能换空间
小技巧:如果你不确定当前平台的对齐方式,可以用offsetof宏来检查每个字段的偏移量。
1.4 跨平台结构体序列化——实战避坑
序列化是跨平台通信的核心。说白了,就是把内存里的结构体,变成一串字节流,让对方能正确解析。这里坑特别多。
我曾经写过一个网络通信模块,结构体直接memcpy发送。结果在大小端不同的平台之间,整数字节序反了,解析出来全是乱码。嗯,从那以后我学乖了。
// 安全的序列化方式
void serialize_int32(uint8_t* buf, int32_t value) {
buf[0] = (value >> 24) & 0xFF; // 大端序
buf[1] = (value >> 16) & 0xFF;
buf[2] = (value >> 8) & 0xFF;
buf[3] = value & 0xFF;
}
int32_t deserialize_int32(const uint8_t* buf) {
return ((int32_t)buf[0] << 24) |
((int32_t)buf[1] << 16) |
((int32_t)buf[2] << 8) |
buf[3];
}
跨平台序列化的核心原则:
- 固定大小:所有字段用int32_t、uint64_t等固定宽度类型
- 固定字节序:统一用大端序(网络字节序)传输
- 固定对齐:序列化时按1字节打包,不要依赖编译器对齐
- 版本控制:结构体头部加版本号,方便后续扩展
避坑指南:我曾经在升级协议时,忘了加版本号。新老设备之间数据解析全乱套。后来所有结构体头部都加一个magic number和版本字段,再也没出过问题。
知识体系总览
下面这张图,帮你理清本章的核心逻辑:
总结一下:数据类型和字节对齐,是跨平台开发的第一道坎。记住三个要点——用固定宽度类型、理解对齐规则、序列化时统一字节序。做到这三点,大部分跨平台问题都能避免。
可可精品资料库