如何在嵌套的 C 结构中使用灵活的数组成员?

How to use flexible array members in nested C structs?

相关:

我正在尝试将一些数据解析为结构。数据包含的信息组织如下:

struct unit {

    struct unit_A {
        // 28 bytes each

        // dependency r6scA 1
        char dr6scA1_tagclass[4];
        uint32_t dr6scA1_tagnamepointer;
        uint32_t dr6scA1_tagnamestringlength;
        uint32_t dr6scA1_tagid;

        // 12 bytes of 0x00

    }A;

    // A strings

    struct unit_B {
        // 48 bytes each

        // dependency r6scB 1
        char dr6scB1_tagclass[4];
        uint32_t dr6scB1_tagnamepointer;
        uint32_t dr6scB1_tagnamestringlength;
        uint32_t dr6scB1_tagid;

        // 32 bytes of 0x00

    }B;

    // B strings

    // unit strings

}unit_container;

你可以忽略奇怪的命名法。

我的行注释 // A strings// B strings// unit strings 都包含以 null 结尾的 C 字符串,其数量与 unit_Aunit_B,并且 unit 结构条目存在于数据中。因此,如果 unit_container 中有 5 个 A 条目,那么在 // A strings.

的位置就会有 5 个 C 字符串

由于我不能在这些位置使用灵活的数组成员,我应该如何解释数据中这些位置基本上是未知数量的可变长度 C 字符串

例如,这些位置的数据可能是:

"The first entry is here.[=72=]Second entry[=72=]Another![=72=]Fourth.[=72=]This 5th entry is the bestest entry evah by any reasonable standards.[=72=]"

...我希望我应该将其解释为:

char unit_A_strings[]

...但这是不可能的。我有哪些选择?

感谢您的考虑。

编辑:

目前我认为最有吸引力的选项是:

char** unit_A_strings; 指向一个 char 字符串数组。

如果我这样做: char unit_A_strings[1]; 来定义一个固定大小为 1 个字符的字符数组,那么我必须放弃 sizeof(unit) 等,否则内存分配大小就会很麻烦,即使它对目前的数据类型来说是最准确的。如果我做 char * unit_A_strings[1];.

也会出现同样的情况

另一个问题:使用char *unit_A_strings;char** unit_A_strings;有什么区别?

结论:

主要问题是结构用于固定大小的信息,而我需要的是可变大小的信息内存区域。所以我不能合法地将数据存储到结构中——至少不能 as 结构。这意味着任何其他解释都可以,在我看来 char** 是这种结构情况的最佳选择。

我认为它可以改用 char** (或者您可以编写一些结构来包装它)。 例如,您可以编写一个帮助函数来解码您的流。

char** decodeMyStream(uint_8* stream, unsigned int* numberOfCString)
{
    *numberOfCString = decodeNumberOfCString(stream);
    char** cstrings = malloc((*numberOfCString) * sizeof(char*));
    unsigned int start = 0;
    for (unsigned int i = 0; i < *numberOfCString; ++i)
    {
        usigned int len = calculateIthStringLength(stream, start)
        cstrings[i] = malloc((len) * sizeof(char));
        memcpy(cstrings[i], stream + start, len); 
        start += len
    }
    return cstrings;
}

只是没有思考示例代码,你可以想出更多更好的算法。

我认为最接近的方法是提供一个字符串数组:

char *AStrings[] = { "The first entry is here.",
                     "Second entry",
                     "Another!",
                     "Fourth.",
                     "This 5th entry is the bestest entry evah by any reasonable standards.",
                     NULL
                   };

注意两点:

  1. AStrings 是一个字符串指针数组 - 它将是 6 个(见下面的 2.)连续指针指向实际字符串,而不是您在中使用的 'compound' 字符串你的榜样。
  2. 我用 NULL 指针结束了 AStrings,以解决 "when do I finish?" 问题。

因此您可以 "fall off the end" of A 并开始查看位置作为指针 - 但要小心!编译器可能会在一个变量和下一个变量之间放入各种填充,从而破坏关于它们在内存中彼此相对位置的任何假设 - 包括重新排序它们!

编辑 哦!我只是有一个想法。另一个可能有帮助的数据表示本质上是你所做的。我已经 'prettied' 提高了一点:

char AString[] = "The first entry is here.[=11=]"
                 "Second entry[=11=]"
                 "Another![=11=]"
                 "Fourth.[=11=]"
                 "This 5th entry is the bestest entry evah by any reasonable standards.[=11=]";
  • C 编译器将自动连接两个 'adjacent' 字符串,就好像它们是一个字符串一样 - 在它们之间有 no NUL 字符。我特意放在上面了。
  • C 编译器会自动将 '[=17=]' 放在任何字符串的末尾 - 在上例中的分号 (;) 处。这意味着该字符串实际上以两个 NUL 字符结尾,而不是一个。

您可以使用该事实来跟踪您在解析字符串时的位置 'array' - 假设每个所需的值都有一个长度大于零的(子)字符串!一旦遇到零长度(子)字符串,您就知道已经到达字符串的末尾 'array'.

我将这些字符串称为 ASCIIZZ 字符串(所有末尾都带有第二个 NUL 的 ASCIIZ 字符串)。