2012-10-15 130 views
1

假设我有结构用C这样与结构阵列结构的劈

struct A { 
int len; 
char s[1]; 
} 

我想有上述结构的阵列,但结构A的char s[1]构件可以是可变长度的。我们应该怎么做?即使C99中的struct hack技巧在这里似乎也不起作用。一种解决方案是将char *作为最后一个成员并进行动态内存分配,但我希望struct的所有数据位于连续的位置,因为我的实现需要缓存不经意。

+2

这只是C99之前的“黑客”,如果你在C90中这样做,任何事情都可能发生。在C99中,它是一个定义明确的特性,被称为_flexible array member_。 – Lundin

回答

5

你不能拥有一个可变大小的对象数组,所以你不能拥有一个使用struct hack的结构数组。数组中的所有对象必须具有相同的大小。如果它们的大小完全相同,则结构必须隐含大小,因此毕竟不会使用struct hack;在结构中数组s的维度中将会有一个非1的大小(除非1大到足够大)。原因在于a[i]的存储位置(其中a是数组的名称,而i是数组中的索引)必须可计算为'a的字节地址加上(i乘以数组中的一个对象的大小)'。所以数组中对象的大小(在本例中是结构体)必须是已知的并且是固定的。

作为替代方案,您可以有一个指向可变大小对象的指针数组;您只需安排分配适当大小的每个对象,并将指针保存到数组中。

需要注意的是C99摒弃了“结构黑客”(这是从未正式便携,但实际上它是),并介绍了“灵活数组成员”,而不是:

struct A { 
    int len; 
    char data[]; 
}; 

然而,上面还建议适用。

+0

那么在这种情况下,它不能是结构数组,它将是指向结构的指针数组... –

+0

正确;我澄清了我的答案(我希望)强调为什么它必须如此。 –

+0

由于struct padding字节,它在实践中从不可移植。无论何时从具有类似架构的平台(如Windows和Linux之间的平台)移植,它都可能正常工作。如果你从8位微控制器移植到Windows,你很可能会遇到问题,因为它们会有完全不同的对齐要求。 – Lundin

1

如果存在“s”的最大尺寸,则可以使用该尺寸代替[1]。这使得一切都保持连续。

如果你真的不想使用动态内存,那么你不能使用数组。你需要你自己的“管理员”,它将单独使用每个成员的结构黑客技巧 - 但这意味着你不能进行索引查找 - 你必须查看每个元素,看看它有多大,并跳转正确的字节数到下一个元素。

+0

我想到了这一点,我想如果我没有得到更好的东西,我必须这样做.. –

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[]和任何填充)前端的总大小....