题
结构似乎是解析二进制blob数据(即文件或网络数据包)的有用方法。在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行代码的情况下逃脱。有什么想法吗?
谢谢, 斯蒂芬
解决方案
您不能拥有多个可变大小的数组。编译时编译器应该如何知道friend []所在的位置? friend的位置取决于data []的大小,并且在编译时数据的大小是未知的。
其他提示
这是一个非常危险的构造,我建议反对它。当结构为LAST元素时,只能在结构中包含一个可变长度数组,当你这样做时,你必须确保分配足够的内存,例如:
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;
}
你不能 - 至少不是以你正在尝试的简单方式。结构末尾的unsized数组基本上是结构末尾的偏移量,没有内置的方法来查找结尾。
所有字段在编译时都会转换为数字偏移量,因此需要在此时进行计算。
到目前为止,答案严重过于复杂化了一个简单的问题。 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];
对于您正在做的事情,您需要格式化的编码器/解码器。解码器获取原始数据并填写您的结构(在您的情况下为数据的每个部分的副本分配空间),并且解码器写入原始二进制文件。
('使用std :: vector')
编辑:
在阅读反馈时,我想我应该扩大我的答案。您可以在结构中有效地拟合两个可变长度数组,如下所示,当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()等为您提供了长度,并且&amp; 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...