无法正确地将char数组memcpy到struct

时间:2014-04-23 18:24:29

标签: c++ char bytearray deserialization memcpy

所以我有一个名为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);
    }

2 个答案:

答案 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,依此类推。