You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:52:51