假设我在C中有这样的结构
struct A {
int len;
char s[1];
}
我想拥有一个上面结构的数组,但结构A的char s[1]
成员可以是可变长度的。我们应该怎么做?即使是C99中的struct hack技巧似乎也不适用于此。一种解决方案是将char *
作为最后一个成员并进行动态内存分配,但我希望struct
的所有数据都在连续的位置,因为我的实现需要缓存不经意。
答案 0 :(得分:5)
您不能拥有可变大小对象的数组,因此您不能使用struct hack拥有结构数组。数组中的所有对象必须具有相同的大小。如果它们的大小都相同,那么结构必须隐含大小,所以你毕竟不会使用struct hack;在你的结构中,数组s
的维度中将有一个不是1的大小(除非1对于所有内容都足够大)。原因是a[i]
的存储位置(其中a
是数组的名称而i
是数组的索引)必须可以计算为{{1的字节地址加上(a
倍数组中一个对象的大小)'。因此,必须知道并修复数组中对象的大小(在本例中为结构)。
作为替代方案,您可以拥有一个指向可变大小对象的指针数组;您只需安排以适当的大小分别分配每个对象,并将指针保存到数组中的指针。
请注意,C99取消了'struct hack'(虽然在实践中它从未正式移植过),而是引入了“灵活的阵列成员”:
i
但是,上述建议仍然适用。
答案 1 :(得分:1)
如果“s”的最大大小,您可以使用它而不是[1]。这使一切都保持连续。
如果您确实不想使用动态内存,那么您无法使用数组。您需要自己的“管理器”,它将单独使用每个成员上的struct hack技巧 - 但这意味着您无法进行索引查找 - 您必须查看每个元素以查看它有多大并跳转正确的字节数到下一个元素。
答案 2 :(得分:1)
在C中,数组索引涉及将基址乘以单个元素的编译时常量大小。因此,您不能直接使用内置数组支持“struct hack”,因为每个s
元素将完全分配您请求的1个字节,并且在结构之后的索引将访问{{1数组中的元素(或完全消失,可能崩溃)。
如果确实需要连续数据以获得缓存访问速度,您可以自己打包,您可以通过间接解决这个问题(就像大多数事情一样)...有一个连续的数组{{ 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
和任何填充)的总大小....