如何在嵌套的 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_A
、unit_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
};
注意两点:
AStrings
是一个字符串指针数组 - 它将是 6 个(见下面的 2.)连续指针指向实际字符串,而不是您在中使用的 'compound' 字符串你的榜样。
- 我用
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 字符串)。
相关:
我正在尝试将一些数据解析为结构。数据包含的信息组织如下:
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_A
、unit_B
,并且 unit
结构条目存在于数据中。因此,如果 unit_container
中有 5 个 A
条目,那么在 // A strings
.
由于我不能在这些位置使用灵活的数组成员,我应该如何解释数据中这些位置基本上是未知数量的可变长度 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
};
注意两点:
AStrings
是一个字符串指针数组 - 它将是 6 个(见下面的 2.)连续指针指向实际字符串,而不是您在中使用的 'compound' 字符串你的榜样。- 我用
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 字符串)。