代码之家  ›  专栏  ›  技术社区  ›  Stefan Mai

取消引用结构中的可变大小数组

  •  2
  • Stefan Mai  · 技术社区  · 17 年前

    结构似乎是解析二进制数据块(即文件或网络包)的有用方法。在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行代码就可以逃走。有什么想法吗?

    谢谢, 斯特凡

    6 回复  |  直到 13 年前
        1
  •  3
  •   Mecki    17 年前

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

        2
  •  3
  •   Adam Rosenfield    17 年前

    这是一个非常危险的结构,我建议不要这样做。当结构是最后一个元素时,只能在结构中包含一个可变长度数组,当您这样做时,必须确保分配足够的内存,例如:

    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;
    }
    
        3
  •  1
  •   Douglas Leeder    17 年前

    你不能-至少不能用你正在尝试的简单方法。结构末尾的非大小化数组基本上是到结构末尾的偏移量,没有内置方式来查找结尾。

    所有字段在编译时都转换为数值偏移量,因此需要在那时进行计算。

        4
  •  1
  •   Jim Buck    13 年前

    到目前为止,答案是严重地过度复杂化了一个简单的问题。麦基说得对,为什么它不能像你想做的那样做,但是你可以做得非常相似:

    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];
    
        5
  •  0
  •   Greg Rogers    17 年前

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

        6
  •  -1
  •   fizzer    17 年前

    (以前是'use std::vector')

    编辑:

    在阅读反馈时,我想我应该扩大我的答案。您可以在结构中有效地容纳两个可变长度的数组,如下所示,当文件数据超出范围时,将自动释放存储空间:

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

    您必须从文件中逐段填充文件数据—读取每个缓冲区的长度,在目标向量上调用resize(),然后读取数据。(有一些方法可以更有效地做到这一点。在磁盘文件I/O的上下文中,我假设这无关紧要)。

    顺便说一句,OP的技术不正确,即使是在他的“漂亮漂亮”的情况下,例如,最后只有一个VLA。

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

    无法保证文件_数据与nodeheader类型正确对齐。更倾向于通过malloc()获取文件\u数据,它保证返回一个与任何类型对齐的指针,或者(更好)首先声明缓冲区是正确的类型:

    struct biggestnodeheader {
        int flags;
        int data_size;
        char data[ENOUGH_SPACE_FOR_LARGEST_HEADER_I_EVER_NEED];
    };
    
    biggestnodeheader file_data;
    // etc...