假設我有結構用C這樣與結構陣列結構的劈
struct A {
int len;
char s[1];
}
我想有上述結構的陣列,但結構A的char s[1]
構件可以是可變長度的。我們應該怎麼做?即使C99中的struct hack技巧在這裏似乎也不起作用。一種解決方案是將char *
作爲最後一個成員並進行動態內存分配,但我希望struct
的所有數據位於連續的位置,因爲我的實現需要緩存不經意。
假設我有結構用C這樣與結構陣列結構的劈
struct A {
int len;
char s[1];
}
我想有上述結構的陣列,但結構A的char s[1]
構件可以是可變長度的。我們應該怎麼做?即使C99中的struct hack技巧在這裏似乎也不起作用。一種解決方案是將char *
作爲最後一個成員並進行動態內存分配,但我希望struct
的所有數據位於連續的位置,因爲我的實現需要緩存不經意。
你不能擁有一個可變大小的對象數組,所以你不能擁有一個使用struct hack的結構數組。數組中的所有對象必須具有相同的大小。如果它們的大小完全相同,則結構必須隱含大小,因此畢竟不會使用struct hack;在結構中數組s
的維度中將會有一個非1的大小(除非1大到足夠大)。原因在於a[i]
的存儲位置(其中a
是數組的名稱,而i
是數組中的索引)必須可計算爲'a
的字節地址加上(i
乘以數組中的一個對象的大小)'。所以數組中對象的大小(在本例中是結構體)必須是已知的並且是固定的。
作爲替代方案,您可以有一個指向可變大小對象的指針數組;您只需安排分配適當大小的每個對象,並將指針保存到數組中。
需要注意的是C99摒棄了「結構黑客」(這是從未正式便攜,但實際上它是),並介紹了「靈活數組成員」,而不是:
struct A {
int len;
char data[];
};
然而,上面還建議適用。
那麼在這種情況下,它不能是結構數組,它將是指向結構的指針數組... –
正確;我澄清了我的答案(我希望)強調爲什麼它必須如此。 –
由於struct padding字節,它在實踐中從不可移植。無論何時從具有類似架構的平臺(如Windows和Linux之間的平臺)移植,它都可能正常工作。如果你從8位微控制器移植到Windows,你很可能會遇到問題,因爲它們會有完全不同的對齊要求。 – Lundin
如果存在「s」的最大尺寸,則可以使用該尺寸代替[1]。這使得一切都保持連續。
如果你真的不想使用動態內存,那麼你不能使用數組。你需要你自己的「管理員」,它將單獨使用每個成員的結構黑客技巧 - 但這意味着你不能進行索引查找 - 你必須查看每個元素,看看它有多大,並跳轉正確的字節數到下一個元素。
我想到了這一點,我想如果我沒有得到更好的東西,我必須這樣做.. –
在C中,數組索引包括將基地址乘以單個元素的編譯時常量大小。因爲這個原因,你不能直接用「struct hack」來使用內置的數組支持,因爲每個s
元素將被精確地分配給你請求的1個字節,並且超越結構的索引將訪問數組中的S
元素(或完全消失,可能會崩潰)。
如果你真的需要緩存訪問速度連續數據,你可以自己收拾它,就可以解決這個(最喜歡的東西)與間接...有S*
連續陣列,並手動收拾你數據到另一個連續緩衝區(malloc()
或堆棧分配足夠的內存用於所有的S
對象,包括所有s[]
成員的實際數據大小)。如果int len
元素沒有針對您的架構進行最佳(正確)對齊,您的性能可能會受損(或您的操作系統崩潰),因此您可能需要在S
實例之間手動填充。
S* index[100] char data[10000];
(S*)(data) --------------> S with 14-byte s[] using data[0]..[17]
(S*)(data + 20) -----\ 2 byte padding so next S is 4-byte aligned
(S*)(data + 32) --\ \---> S with 7-byte s[] using data[20]..[30]
\ 1 byte padding...
\-----> ...
不幸的是,這是相當不靈活的數據佈局 - 你不能只生長在一個元素的s
成員的數據量,而不schuffling所有其他數據的方式進行,並修補指數,但這是正常的對於數組,如果你已經在考慮使用它們,那麼這可能適合你。另一個麻煩是計算S
結構(包括s[]
和任何填充)前端的總大小....
這只是C99之前的「黑客」,如果你在C90中這樣做,任何事情都可能發生。在C99中,它是一個定義明確的特性,被稱爲_flexible array member_。 – Lundin