所以我有一个名为packet
的结构struct Packet {
unsigned int packet_type;
wchar_t packet_length[128];
wchar_t file_name[256];
wchar_t template_name[256];
wchar_t file_name_list[1024];
wchar_t file_data[1024];
void serialize(char * dat) {
memcpy(dat, this, sizeof(Packet));
}
void deserialize(const char * dat) {
memcpy(this, dat, sizeof(Packet));
}
};
我试图从这些数据中贬低
{byte[2692]}
[0] 0 unsigned int packet_type; (4 bytes)
[1] 0
[2] 0
[3] 0
[4] 50 '2' wchar_t packet_length[128]; (128 bytes)
[3] 0
[5] 54 '6'
[3] 0
[6] 57 '9'
[3] 0
[7] 50 '2'
[8] 0
[...] 0
[132] 112 'p' wchar_t file_name[256]; (256 bytes)
[133] 0
[134] 104 'h'
[...] 0
但deserialze中的memcpy并没有给我file_name,但它确实给了我packet_length。这有什么用?谢谢!
编辑: 所以现在我很清楚,wchar_t比我想象的要占用更多的空间;但是,我被告知不要使用memcpy吗?
我已经编写了这个反序列化方法,它正确地抓取了数据。这会导致安全漏洞吗?
void deserialize(const char * dat) {
memcpy(&(packet_type), dat, 4);
memcpy(&(packet_length[0]), dat + 4, 128);
memcpy(&(file_name[0]), dat + 132, 256);
memcpy(&(template_name[0]), dat + 388, 256);
memcpy(&(file_name_list[0]), dat + 644, 1024);
memcpy(&(file_data[0]), dat + 1668, 1024);
}
答案 0 :(得分:5)
请不要使用此方法来序列化结构。这完全不便携。
此外,编译器还可以根据目标体系结构,字节序,优化和其他一些东西来填充,对齐或重新排序成员。
更优雅的方式是使用 boost::Serialization ,以便携方式处理低级细节。
另一方面,如果你只想检查你的结构,那么调试器会很方便......
答案 1 :(得分:2)
char
数组的布局假设wchar_t
的大小是两个字节;它不是 - 这是wchar_t
的大小为4
的系统示例,因此Packet
的大小为10756
,而不是2692
字节:(link to a demo)。
这就是为什么编辑中的memcpy
技巧会出现问题:它假定char[]
数组中的数据布局与wchar_t[]
数组的布局相匹配,它可能是可能不匹配。如果您知道数据数组具有以小端格式存储的双字符元素(LSB优先),您可以编写自己的函数将数据从源转换为目标,并调用它以获取部分序列化数据,如这样:
void bytes_to_wchar(wchar_t *dest, const unsigned char* src, size_t length) {
for (size_t i = 0 ; i != lengt ; i++) {
dest[i] = src[2*i] | (src[2*i+1] << 8);
}
}
现在,您可以使用此函数将数据复制到wchar_t
数组中,而与目标系统上的wchar_t
大小或目标系统的字节顺序无关:
void deserialize(const char * dat) {
bytes_to_wchar(packet_type, dat + 0, 4);
bytes_to_wchar(packet_length[0], dat + 4, 128);
bytes_to_wchar(file_name[0], dat + 132, 256);
bytes_to_wchar(template_name[0], dat + 388, 256);
bytes_to_wchar(file_name_list[0], dat + 644, 1024);
bytes_to_wchar(file_data[0], dat + 1668, 1024);
}
使用相同的编译器在同一硬件上执行此操作时,可以使用从内存中保存数据并将其写回的快捷方式。即使这样,它仍然对您使用的标头和编译器设置中的小调整很敏感。
如果您需要复制到struct
的字符数组具有固定布局,则需要编写一个函数来处理该布局,将两个字节的组转换为wchar_t
个,四个 - 字节组分为unsigned int
,依此类推。