如何在C中将二进制数据读入带内存对齐的结构体(无需逐个memcpy)
C语言中优雅导入紧凑二进制数据至带对齐结构体的方案
首先给出定义的结构体:
typedef struct { uint8_t type; // 1B -> 累计1B uint16_t hash; // 2B -> 累计3B uint16_t id; // 2B -> 累计5B uint32_t ip; // 4B -> 累计9B uint16_t port; // 2B -> 累计11B } Data;
磁盘上存储的紧凑二进制数据:
const unsigned char blob[11] = { 0x00, 0x00, 0x7b, 0x00, 0xea, 0x00, 0x00, 0x00, 0x59, 0x01, 0x00 };
由于结构体存在内存对齐,sizeof(Data)为16字节,内存布局和磁盘上的紧凑数据不一致,无法直接通过Data *data = (Data *)blob强制转换。下面提供两种无需逐个字段memcpy的简洁方案:
方案一:使用编译指令取消结构体对齐
通过编译器特定指令让结构体按紧凑布局存储,此时sizeof(Data)会变为11字节,和磁盘数据长度一致,直接整体拷贝即可。
适用于MSVC、GCC等主流编译器的写法:
#pragma pack(push, 1) // 保存当前对齐设置,改为1字节对齐 typedef struct { uint8_t type; uint16_t hash; uint16_t id; uint32_t ip; uint16_t port; } Data; #pragma pack(pop) // 恢复原对齐设置 // 直接整体拷贝 Data data; memcpy(&data, blob, sizeof(Data));
GCC专属简化写法:
typedef struct __attribute__((packed)) { uint8_t type; uint16_t hash; uint16_t id; uint32_t ip; uint16_t port; } Data; // 整体拷贝 Data data; memcpy(&data, blob, sizeof(Data));
注意:该方案依赖编译器实现,移植性略有局限;同时取消对齐可能导致CPU访问结构体字段时性能下降(部分架构甚至会触发未对齐访问错误),若对性能敏感需谨慎使用。
方案二:使用联合体(Union)映射
定义一个包含紧凑结构体和字节数组的联合体,利用联合体内存共享特性完成数据映射:
#pragma pack(push, 1) typedef struct { uint8_t type; uint16_t hash; uint16_t id; uint32_t ip; uint16_t port; } CompactData; #pragma pack(pop) typedef union { CompactData data; unsigned char blob[11]; } DataUnion; // 使用方式 DataUnion du; memcpy(du.blob, blob, sizeof(du.blob)); // 此时du.data就是填充好的结构体数据,可直接访问du.data.type、du.data.hash等字段
本质上该方案和方案一原理一致,只是通过联合体包装了一层,方便直接操作字节数组和结构体。
内容的提问来源于stack exchange,提问作者pqzpkaot
相关产品推荐
相关产品推荐

