我有一个结构
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中的表示可能与磁盘上的压缩表示不同。
那么,我如何才能将我的blob“导入”到一个Data结构体中,而不必为每个属性使用memcpy
呢?
3条答案
按热度按时间k75qkfdt1#
点是
sizeof(Data) == 16
,RAM中的表示可能与磁盘上的压缩表示不同。由于不能依赖文件中的数据布局来匹配内存中结构的数据布局,因此标准C不提供逐个成员工作的替代方法。
但是从磁盘阅读数据可能与从数组中阅读数据是不同的问题。我想你想象阅读一个或多个完整的原始记录到内存中,然后以某种方式从那里复制,但是如果你可以依靠结构和磁盘之间匹配的各个字段的大小和字节序,那么你可以考虑这个:
字符串
这让流处理缓冲(它会处理缓冲,除非你禁用它),减轻你对字节数的计数,并且非常清楚。五次调用
fread()
可能比五次调用memcpy()
稍微贵一点,但是你不太可能注意到打开文件和从中传输数据的成本的差异。但是,如果您确实需要从包含文件原始字节的内存数组中填充结构,那么每个成员
memcpy()
是最可移植的方法,而且可能比您想象的更有效。velaa5lx2#
假设blob数组中的右侧字节对应于比左侧字节更高的权重,那么,一个简单的解决方案将是按以下方式使用按位运算符:
字符串
mdfafbf13#
避免这种特殊结构的多次读取或字节复制的最简单方法是显式地用3个初始字节和2个尾随字节填充结构:
字符串
你可以用一个
fread
读取数据:型
从内存blob调用也是对
memcpy
的单个调用:型
阅读二进制数据需要以二进制模式打开文件
"rb"
,"wb"
.在单个
fwrite
中写入数据是通过型
这个技巧适用于中的结构,但在其他情况下可能不起作用:
因此,在一般情况下,您可能必须使用
memcpy
将面向紧凑字节的表示的块复制到内存中使用的结构中,调整潜在的字节顺序差异。具有小的固定大小的memcpy
通常会有效地进行内联扩展,生成很少的指令,这可以在使用Godbolt Compiler Explorer时进行验证。