簡體   English   中英

無法正確地將char數組memcpy到struct

[英]Cannot properly memcpy a char array to struct

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

請不要使用此方法來序列化結構。 這完全不便攜。

此外,編譯器還可以根據目標體系結構,字節序,優化和一堆其他內容來填充,對齊或重新排序成員。

更優雅的方法是使用boost :: Serialization ,它以便攜方式處理低級細節。

另一方面,如果你只是想檢查你的結構,那么調試器就派上用場了......

char數組的布局假定wchar_t的大小是兩個字節; 它不是 - 這里是wchar_t的大小為4的系統的示例,因此Packet的大小是10756 ,而不是2692字節:( 鏈接到演示 )。

這就是為什么編輯中的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 ,依此類推。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM