考虑此代码:
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**
),即默认情况下初始化为NULL
?
此目的:能够在API的实现中使用相同的逻辑(在此示例中为f_01
),并为char**
指针和NULL
使用empty arrays
参数。即在API中,没有其他if (! *flags)
检查,因为预计如果flags != NULL
则为non-empty array
。这是合乎逻辑的,对吗?那么,为什么需要添加其他if (! *flags)
检查来处理empty arrays
?是否可以通过某种方式将empty array
评估为C中的NULL
指针?
结构之所以没有将flags
初始化为NULL
的原因是,最后一个标志是“ flexible array member”而不是指针。 struct是一种为要放入其中的所有事物分配足够空间的方法。因此,当结构具有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.118-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
。但这绝对是错误的方法。