簡體   English   中英

零長度數組

[英]Array of zero length

我正在重構一些舊代碼,發現很少包含零長度數組的結構(如下)。 當然,編譯指示會壓制警告,但是我無法通過包含此類結構的“新”結構來創建(錯誤2233)。 數組“ byData”用作指針,但是為什么不使用指針呢? 或長度為1的數組? 當然,沒有添加任何注釋使我喜歡此過程...使用此類東西的任何原因? 在重構這些方面有什么建議嗎?

struct someData
{
   int nData;
   BYTE byData[0];
}

注意:這是C ++,Windows XP,VS 2003

是的,這是C-Hack。
要創建任意長度的數組:

struct someData* mallocSomeData(int size)
{
    struct someData*  result = (struct someData*)malloc(sizeof(struct someData) + size * sizeof(BYTE));
    if (result)
    {    result->nData = size;
    }
    return result;
}

現在,您有了一個具有指定長度的數組的someData對象。

不幸的是,有幾個原因導致您在結構末尾聲明零長度數組。 從本質上講,它使您能夠具有從API返回的可變長度結構。

雷蒙德·陳(Raymond Chen)在該主題上發表了出色的博客文章。 我建議您看一下這篇文章,因為它可能包含您想要的答案。

請注意,在他的文章中,它處理的是大小為1而不是0的數組。 之所以如此,是因為零長度數組是標准中更新的條目。 他的帖子仍然適用於您的問題。

http://blogs.msdn.com/oldnewthing/archive/2004/08/26/220873.aspx

編輯

注意:即使Raymond的帖子說0長度數組在C99中是合法的,但實際上在C99中仍然不合法。 您應該使用長度為1的數組,而不是長度為0的數組

這是一個古老的C語言,可允許使用大小靈活的數組。

在C99標准中,這不是必需的,因為它支持arr []語法。

您對“為什么不使用大小為1的數組”的直覺很明顯。

代碼做錯了“ C struct hack”,因為零長度數組的聲明違反了約束。 這意味着編譯器可以在編譯時立即通過一條診斷消息來停止您的黑客攻擊,該消息會停止翻譯。

如果要進行黑客入侵,則必須將其通過編譯器。

進行“ C struct hack”(與自1989年ANSI C以來的C語言方言兼容,並且可能更早)的正確方法是使用大小為1的完全有效的數組:

struct someData
{
   int nData;
   unsigned char byData[1];
}

此外,代替sizeof struct someData ,使用以下方法計算byData之前的部分的大小:

offsetof(struct someData, byData);

要分配struct someData與42個字節的空間byData ,我們會再使用:

struct someData *psd = (struct someData *) malloc(offsetof(struct someData, byData) + 42);

請注意,即使在數組大小為零的情況下,此offsetof計算實際上也是正確的計算。 您會看到,整個結構的sizeof可以包含填充。 例如,如果我們有這樣的事情:

struct hack {
  unsigned long ul;
  char c;
  char foo[0]; /* assuming our compiler accepts this nonsense */
};

由於ul成員, struct hack的大小很可能被填充以進行對齊。 如果unsigned long是四個字節寬,則sizeof (struct hack)很可能為8,而offsetof(struct hack, foo)幾乎可以確定為offsetof方法是獲取結構前面部分准確大小的方法。就在數組之前

這樣便可以重構代碼:使其符合經典的,高度可移植的struct hack。

為什么不使用指針? 因為指針占用額外的空間,所以必須進行初始化。

還有其他不使用指針的充分理由,即,指針需要一個地址空間才能有意義。 struct hack是可外部化的:也就是說,在某些情況下,此類布局與外部存儲(例如文件,數據包或共享內存)相符,在這種情況下,您不需要指針,因為它們沒有意義。

幾年前,我在內核和用戶空間之間的共享內存消息傳遞接口中使用了struct hack。 我不希望指針在那里,因為它們只會對生成消息的進程的原始地址空間有意義。 該軟件的內核部分使用其在不同地址的映射來查看內存,因此所有內容均基於偏移量計算。

值得指出的是,IMO是進行尺寸計算的最佳方法,該方法已在上面鏈接的Raymond Chen文章中使用。

struct foo
{
    size_t count;
    int data[1];
}

size_t foo_size_from_count(size_t count)
{
    return offsetof(foo, data[count]);
}

第一個條目偏離所需分配結束的偏移量也是所需分配的大小。 IMO,這是一種非常優雅的尺寸計算方法。 可變大小數組的元素類型是什么都沒有關系。 offsetof(或Windows中的FIELD_OFFSET或UFIELD_OFFSET)始終以相同的方式編寫。 沒有sizeof()表達式會導致混亂。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM