1

结构似乎是解析二进制数据块(即文件或网络数据包)的有用方法。在 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 行代码就能摆脱困境。有任何想法吗?

谢谢,斯特凡

4

6 回答 6

3

您不能有多个可变大小的数组。编译器在编译时应该如何知道friend[]的位置?友元的位置取决于 data[] 的大小,而数据的大小在编译时是未知的。

于 2008-10-07T15:02:57.863 回答
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;
}
于 2008-10-07T15:06:49.697 回答
1

你不能——至少不能以你尝试的简单方式。结构末尾的未调整大小的数组基本上是结构末尾的偏移量,没有内置方法来查找结尾。

所有字段都在编译时转换为数字偏移量,因此它们需要在当时是可计算的。

于 2008-10-07T15:05:17.983 回答
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];
于 2008-10-09T07:31:13.280 回答
0

对于您正在做的事情,您需要格式的编码器/解码器。解码器获取原始数据并填写您的结构(在您的情况下为数据的每个部分的副本分配空间),解码器写入原始二进制文件。

于 2008-10-07T15:21:40.807 回答
-1

(是“使用 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() 等为您提供长度,&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...
于 2008-10-07T15:08:40.800 回答