2008-10-07 58 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];