C 将二进制数据读入结构体

问题描述 投票:0回答:2

我有一个结构

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 };

我想将

blob
“读”到我的结构中,第一个字节
0x00
对应于
type
,第二个和第三个字节
0x00, 0x7b
对应于
hash
,等等

我不能只做

Data *data = (Data *)blob
,因为
Data
的实际大小可能会大于
11
字节(更快的RAM访问或其他东西。这里不相关。)重点是
sizeof(Data) == 16
和中的表示RAM 可能与磁盘上的紧凑型 RAM 不同。

那么如何将我的 blob“导入”到数据结构中,而不必为每个属性使用

memcpy
呢? C 语言中最好/最简单的解决方案是什么?

c struct binary-data
2个回答
0
投票

重点是

sizeof(Data) == 16
,RAM 中的表示可能与磁盘上的紧凑表示不同。

由于您不能依赖文件中的数据布局来匹配内存中结构的数据布局,因此标准 C 不提供按成员工作的替代方案。

但是从磁盘读取数据可能与从数组读取数据是不同的问题。我想您想象将一个或多个完整原始记录读入内存,然后以某种方式从那里复制,但如果您可以依赖结构和磁盘之间匹配的各个字段的大小和字节顺序,那么您可以考虑这一点:

Data item;

if (fread(&item.type, sizeof(item.type), 1, input_file) == 0) handle_error();
if (fread(&item.hash, sizeof(item.hash), 1, input_file) == 0) handle_error();
if (fread(&item.ip,   sizeof(item.ip),   1, input_file) == 0) handle_error();
if (fread(&item.id,   sizeof(item.id),   1, input_file) == 0) handle_error();
if (fread(&item.port, sizeof(item.port), 1, input_file) == 0) handle_error();

这让流可以处理缓冲(它会处理缓冲,除非您禁用它),使您无需计算字节,而且非常清楚。五次调用

fread()
可能比五次调用
memcpy()
贵一点,但您不太可能注意到打开文件和从中传输数据的成本的差异。

但是,如果您确实需要从包含文件中原始字节的内存数组填充结构,那么每个成员

memcpy()
是最可移植的方式。而且很可能比你想象的更有效率。


0
投票

假设 blob 数组中的右侧字节对应于更高的权重 比左侧字节,那么,一个简单的解决方案是按以下方式使用按位运算符:

void importFromBlob(const unsigned char *blob, Data *data) {
    // Import type
    data->type = blob[0];

    // Import hash 
    data->hash = (blob[1] << 8) | blob[2];  //assembled as 0x007b in your exp

    // Import id 
    data->id = (blob[3] << 8) | blob[4];

    // Import ip 
    data->ip = (uint32_t)(blob[5]) | (uint32_t)(blob[6] << 8) | (uint32_t)(blob[7] << 16) | (uint32_t)(blob[8] << 24);

    // Import port
    data->port = (blob[9] << 8) | blob[10];
}
© www.soinside.com 2019 - 2024. All rights reserved.