2008-10-07 86 views
2

結構似乎是解析二進制數據塊(即文件或網絡數據包)的有用方法。在blob中有可變大小的數組之前,這很好,很花哨。例如:解構結構中的變量大小數組

struct nodeheader{ 
     int flags; 
     int data_size; 
     char data[]; 
}; 

這讓我找到了最後一個數據字符:

nodeheader b; 
cout << b.data[b.data_size-1]; 

問題是,我想有多個變長數組:

struct nodeheader{ 
    int friend_size; 
    int data_size; 
    char data[]; 
    char friend[]; 
}; 

我不是手動分配這些結構。我有一個文件,像這樣:

char file_data[1024]; 
nodeheader* node = &(file_data[10]); 

正如我試圖解析二進制文件(更具體的一個類文件)。我已經用Java編寫了一個實現(這是我的課程任務),不,我正在用C++編寫個人版本,並且希望不必編寫100行代碼即可離開。有任何想法嗎?

感謝, 斯特凡

回答

3

你不能有多個可變大小的數組。編譯器應該如何知道friend []所在的位置?朋友的位置取決於數據的大小[],編譯時數據的大小是未知的。

+0

一個偉大的一點,我的理解,我想我的問題仍然是: 有沒有一個很好的方法來做到這一點?這裏有大量的二進制文件,編寫數百行代碼只是頭文件的一個實現,這是一件很痛苦的事情。 – 2008-10-07 15:15:16

+0

實際上,由於結構體具有填充,所以如果您告訴編譯器不使用填充,則只能使用它來解析打包的二進制數據。在GCC中,你可以通過__attribute __((packed))來做到這一點;只需在Google上搜索即可。 – Mecki 2008-10-07 15:38:28

1

你不能 - 至少不能以你嘗試的簡單方式。結構末尾的未分組數組基本上是結構末端的偏移量,沒有內置的方法來查找結尾。

所有的字段在編譯時轉換爲數字偏移量,所以它們需要在那個時候進行計算。

3

這是一個非常危險的構造,我建議不要這樣做。您只能包含一個結構體的變長數組時,它是最後一個元素,當你這樣做,你必須確保你分配足夠的內存,例如:

nodeheader *nh = (nodeheader *)malloc(sizeof(nodeheader) + max_data_size); 

你想要做的是什麼只要使用正規的動態分配數組:

struct nodeheader 
{ 
    char *data; 
    size_t data_size; 
    char *friend; 
    size_t friend_size; 
}; 

nodeheader AllocNodeHeader(size_t data_size, size_t friend_size) 
{ 
    nodeheader nh; 
    nh.data = (char *)malloc(data_size); // check for NULL return 
    nh.data_size = data_size; 
    nh.friend = (char *)malloc(friend_size); // check for NULL return 
    nh.friend_size = friend_size; 

    return nh; 
} 

void FreeNodeHeader(nodeheader *nh) 
{ 
    free(nh->data); 
    nh->data = NULL; 
    free(nh->friend); 
    nh->friend = NULL; 
} 
-1

(是 '使用std ::矢量')

編輯:

在閱讀的反饋,我想我應該擴大我的回答。你能很好地契合兩個可變長度數組在你的結構如下,當自動file_data超出範圍的存儲空間將被釋放給你:

struct nodeheader { 
    std::vector<unsigned char> data; 
    std::vector<unsigned char> friend_buf; // 'friend' is a keyword! 
    // etc... 
}; 

nodeheader file_data; 

現在file_data.data.size(),等給你長度和和& file_data.data [0]給你一個指向數據的原始指針,如果你需要的話。

您必須從文件中逐個填寫文件數據 - 讀取每個緩衝區的長度,在目標向量上調用resize(),然後讀取數據。 (有辦法更有效地做到這一點。在磁盤文件I/O的情況下,我假設它沒有關係)。

順便說一句,即使他的'精緻和花花公子'的情況下,OP的技術是不正確的,例如,最後只有一個VLA。

char file_data[1024]; 
nodeheader* node = &(file_data[10]); 

有沒有保證file_data正確的nodeheader類型一致。寧可獲得通過的malloc()file_data - 這保證返回的任何類型的對齊的指針 - 或者(更好)宣佈緩衝區是正確的類型在首位的:

struct biggestnodeheader { 
    int flags; 
    int data_size; 
    char data[ENOUGH_SPACE_FOR_LARGEST_HEADER_I_EVER_NEED]; 
}; 

biggestnodeheader file_data; 
// etc... 
0

對於你是什麼你需要一個格式的編碼器/解碼器。解碼器獲取原始數據並填充你的結構(在你的情況下爲每個數據段的副本分配空間),並且解碼器寫入原始二進制數據。

1

迄今爲止的答案嚴重過度複雜化一個簡單的問題。 Mecki是正確的,爲什麼就不能做到你想做到這一點,但你可以做到這一點非常相似:

struct nodeheader 
{ 
    int friend_size; 
    int data_size; 
}; 

struct nodefile 
{ 
    nodeheader *header; 
    char *data; 
    char *friend; 
}; 

char file_data[1024]; 

// .. file in file_data .. 

nodefile file; 
file.header = (nodeheader *)&file_data[0]; 
file.data = (char *)&file.header[1]; 
file.friend = &file.data[file->header.data_size];