C array/pointer 语义:如何使结构内的数组具有相应指针的 properties/semantics?
C array/pointer semantics: how to make an array inside a struct to have properties/semantics of corresponding pointer?
考虑这段代码:
void f_01( int a, char** flags )
{
printf("flags %p\n", flags);
if ( ! flags )
{
return; // early exit
}
//some code
}
struct s01
{
int a;
char** flags1; /* NULL = not used */
char* flags[]; /* NULL = not used */
} s_01 = { 13 };
int main()
{
struct s01* s = &s_01;
f_01( 1, NULL );
f_01( 2, s->flags1 );//for demonstration purpose
f_01( 3, s->flags ); //s->flags is expected to be NULL, but instead
//it evaluates to address of s->flags (i.e. &s->flags)
return 0;
}
实际输出:
f_01 1 (nil)
f_01 2 (nil)
f_01 3 0x601038
预期输出(虚数):
f_01 1 (nil)
f_01 2 (nil)
f_01 3 (nil)
问题:如何让一个数组结构体成员(本例中的flags
)拥有对应指针(本例中的char**
)的properties/semantics,即初始化为默认 NULL
?
这样做的目的:能够在 API 的实现中使用相同的逻辑(在本例中为 f_01
),char**
参数用于 [=17] =] 指针和 empty arrays
。 IE。在 API 中没有额外的 if (! *flags)
检查,因为预计如果 flags != NULL
那么它就是 non-empty array
。这是合乎逻辑的,对吧?那么为什么需要添加额外的 if (! *flags)
检查来处理 empty arrays
? empty array
能否以某种方式评估为 C 中的 NULL
指针?
结构未将 flags
初始化为 NULL
的原因是因为最后一个标志是 "flexible array member" 而不是指针。该结构是一种为您想要放入其中的所有内容分配足够 space 的方法。因此,当结构具有 int a;
、char** flags1;
、char* flags[];
时。它需要分配至少 sizeof(a)
(可能是 16 位)、sizeof(char**)
(可能是 32 位)和 sizeof(char*[])
(在这种特殊情况下未知)的内存块。因为我们还不知道指针数组的大小,所以它会将其视为零位,当您计算出所需的大小时,您需要为数组的大小分配足够的额外位。 (参见 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf §6.7.2.1 18-21)
所以在这种情况下它将 char*
指针初始化为 NULL
因为它没有被赋予一个值并且假设你想要一个大小为零的 char*
数组因为它没有为其大小赋予价值。该数组只是从结构的末尾开始(在您的情况下为 0x601038
)。因此,当您将数组传递给 f_01
时,您就是在给它零数组的起始位置。
我知道您可能不想听到这个,但我能想到的唯一解决方案是将 char* flags[];
替换为 char** flags
。也许您可以将 char* flags[];
更改为 int sizeOfFlags;
和 char* flagData[];
,然后将 sizeOfFlags 填入 f_01。因为 NULL == 0
如果 sizeOfFlags == 0
当大小为零时它仍然会给你 NULL
。然而,这绝对是错误的做法。
考虑这段代码:
void f_01( int a, char** flags )
{
printf("flags %p\n", flags);
if ( ! flags )
{
return; // early exit
}
//some code
}
struct s01
{
int a;
char** flags1; /* NULL = not used */
char* flags[]; /* NULL = not used */
} s_01 = { 13 };
int main()
{
struct s01* s = &s_01;
f_01( 1, NULL );
f_01( 2, s->flags1 );//for demonstration purpose
f_01( 3, s->flags ); //s->flags is expected to be NULL, but instead
//it evaluates to address of s->flags (i.e. &s->flags)
return 0;
}
实际输出:
f_01 1 (nil)
f_01 2 (nil)
f_01 3 0x601038
预期输出(虚数):
f_01 1 (nil)
f_01 2 (nil)
f_01 3 (nil)
问题:如何让一个数组结构体成员(本例中的flags
)拥有对应指针(本例中的char**
)的properties/semantics,即初始化为默认 NULL
?
这样做的目的:能够在 API 的实现中使用相同的逻辑(在本例中为 f_01
),char**
参数用于 [=17] =] 指针和 empty arrays
。 IE。在 API 中没有额外的 if (! *flags)
检查,因为预计如果 flags != NULL
那么它就是 non-empty array
。这是合乎逻辑的,对吧?那么为什么需要添加额外的 if (! *flags)
检查来处理 empty arrays
? empty array
能否以某种方式评估为 C 中的 NULL
指针?
结构未将 flags
初始化为 NULL
的原因是因为最后一个标志是 "flexible array member" 而不是指针。该结构是一种为您想要放入其中的所有内容分配足够 space 的方法。因此,当结构具有 int a;
、char** flags1;
、char* flags[];
时。它需要分配至少 sizeof(a)
(可能是 16 位)、sizeof(char**)
(可能是 32 位)和 sizeof(char*[])
(在这种特殊情况下未知)的内存块。因为我们还不知道指针数组的大小,所以它会将其视为零位,当您计算出所需的大小时,您需要为数组的大小分配足够的额外位。 (参见 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf §6.7.2.1 18-21)
所以在这种情况下它将 char*
指针初始化为 NULL
因为它没有被赋予一个值并且假设你想要一个大小为零的 char*
数组因为它没有为其大小赋予价值。该数组只是从结构的末尾开始(在您的情况下为 0x601038
)。因此,当您将数组传递给 f_01
时,您就是在给它零数组的起始位置。
我知道您可能不想听到这个,但我能想到的唯一解决方案是将 char* flags[];
替换为 char** flags
。也许您可以将 char* flags[];
更改为 int sizeOfFlags;
和 char* flagData[];
,然后将 sizeOfFlags 填入 f_01。因为 NULL == 0
如果 sizeOfFlags == 0
当大小为零时它仍然会给你 NULL
。然而,这绝对是错误的做法。