【问题标题】:How to create a structure with two variable sized arrays in C如何在 C 中创建具有两个可变大小数组的结构
【发布时间】:2009-08-03 18:27:01
【问题描述】:

我正在编写一个轻量级序列化函数,需要在其中包含两个可变大小的数组。

  • 我应该如何跟踪每个的大小?
  • 我应该如何定义结构?
  • 我是不是搞错了?

编辑:结果必须是连续的内存块

【问题讨论】:

    标签: c arrays struct


    【解决方案1】:

    这会解析为类似

    typedef struct
    {
       size_t arr_size_1, arr_size_2;
       char arr_1[0/*arr_size_1 + arr_size_2*/];
    } ...;
    

    大小应该在动态大小数据的前面,以便在扩展数组时它不会移动。

    您的结构中不能有 2 个 unknown 大小的数组,因此您必须将它们折叠成一个,然后从第一个指针访问相对数据。

    【讨论】:

    • 或者,您初始化为指向 arr_1 + [r1 大小] 的 char arr_1[] 和 char* arr_2。
    【解决方案2】:
    typedef struct MyStruct_s
    {
      int variable_one_size;
      void* variable_one_buf;
      int variable_two_size;
      void* variable_two_buf;
    } MyStruct;
    
    MyStruct* CreateMyStruct (int size_one, int size_two)
    {
      MyStruct* s = (MyStruct*)malloc (sizeof (MyStruct));
      s->variable_one_size = size_one;
      s->variable_one_buf = malloc (size_one);
      s->variable_two_size = size_two;
      s->variable_two_buf = malloc (size_two);
    }
    
    void FreeMyStruct (MyStruct* s)
    {
      free (s->variable_one_buf);
      free (s->variable_two_buf);
      free (s);
    }
    

    【讨论】:

    • 结果在内存中必须是连续的
    【解决方案3】:

    由于数据在内存中应该是连续的,因此有必要分配一块大小合适的内存并或多或少地手动管理其内容。您可能最好创建一个包含“静态”信息和相关管理功能的结构,这些功能执行内存管理并提供对结构的“动态”成员的访问权限:

    typedef struct _serial {
      size_t sz_a;
      size_t sz_b;
      char data[1]; // "dummy" array as pointer to space at end of the struct
    } serial;
    
    serial* malloc_serial(size_t a, size_t b) {
      serial *result;
      // malloc more memory than just sizeof(serial), so that there
      // is enough space "in" the data member for both of the variable arrays
      result = malloc(sizeof(serial) - 1 + a + b);
      if (result) {
        result->sz_a = a;
        result->sz_b = b;
      }
      return result;
    }
    
    // access the "arrays" in the struct:
    
    char* access_a(serial *s) {
      return &s->data[0];
    }
    
    char* access_b(serial *s) {
      return &s->data[s->sz_a];
    }
    

    然后你可以这样做:

      serial *s = ...;
      memcpy(access_a(s), "hallo", 6);
      access_a(s)[1] = 'e';
    

    另外请注意,您不能只将一个serial 分配给另一个,您需要确保大小兼容并手动复制数据。

    【讨论】:

    • 感谢您提供实际代码。正如克里斯托弗所展示的那样,我认为您可以通过声明“数据 [0]”而侥幸。如果是这样,那将通过删除一些非一的调整来简化代码。
    【解决方案4】:

    为了序列化可变大小的数据,您必须有某种边界标记。边界标签可以是写在数据之前的大小,也可以是不允许出现在数据流中的特殊值,写在数据之后。

    您选择哪一种取决于您存储的数据量,以及您是否正在优化输出流中的大小。预先存储大小通常更容易,因为您知道接收缓冲区的大小。如果不这样做,则必须在加载时逐渐调整缓冲区的大小。

    【讨论】:

      【解决方案5】:

      在某些方面,我会做 Dan Olson 这样的事情。然而:

      1) 我将创建最终结构,方法是创建一个更简单的结构的两个实例,该结构只有一个变量数组。

      2) 我会用 byte* 声明数组并使用 size_t 作为它的长度。

      话虽如此,我仍然不完全清楚您要做什么。

      编辑

      如果您希望它在内存中连续,只需定义一个具有两个长度的结构。然后为要传递的两个块以及结构本身分配一个足够大的块。设置两个长度,然后立即复制两个块。我认为应该清楚长度如何足以使结构自描述。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-23
        • 1970-01-01
        • 2022-11-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多