假设我在 C 中有这样的结构
struct A {
int len;
char s[1];
}
我想要一个上述结构的数组,但char s[1]
结构 A 的成员可以是可变长度的。我们应该怎么做?甚至 C99 中的 struct hack 技巧在这里似乎也不起作用。一种解决方案是char *
作为最后一个成员并进行动态内存分配,但我希望所有数据都struct
位于连续位置,因为我的实现需要缓存无意识。
假设我在 C 中有这样的结构
struct A {
int len;
char s[1];
}
我想要一个上述结构的数组,但char s[1]
结构 A 的成员可以是可变长度的。我们应该怎么做?甚至 C99 中的 struct hack 技巧在这里似乎也不起作用。一种解决方案是char *
作为最后一个成员并进行动态内存分配,但我希望所有数据都struct
位于连续位置,因为我的实现需要缓存无意识。
你不能有一个可变大小的对象数组,所以你不能有一个使用 struct hack 的结构数组。数组中的所有对象的大小必须相同。如果它们的大小都相同,则结构必须隐含大小,因此您毕竟不会使用 struct hack;在你的结构中数组的维度中会有一个不是 1 的大小s
(除非 1 对所有东西都足够大)。原因是a[i]
(其中a
是数组的名称并且i
是数组的索引)的存储位置必须可以计算为“a
加号的字节地址(i
乘以数组中一个对象的大小)”。因此,数组中对象(在本例中为结构)的大小必须是已知且固定的。
作为替代方案,您可以拥有一个指向可变大小对象的指针数组;您只需安排以适当的大小分别分配每个对象,并将指向该对象的指针保存在数组中。
请注意,C99 取消了“struct hack”(虽然在实践中它从未正式可移植),而是引入了“灵活数组成员”:
struct A {
int len;
char data[];
};
但是,上面的建议仍然适用。
如果“s”有最大尺寸,您可以使用它来代替 [1]。这使一切保持连续。
如果你真的不想使用动态内存,那么你不能用数组来做。您需要自己的“经理”,它将单独对每个成员使用 struct hack 技巧 - 但这意味着您不能进行索引查找 - 您必须查看每个元素以查看它有多大并跳转正确的字节数到下一个元素。
在 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
成员中的数据量而不将所有其他数据排除在外并修补索引,但这对于数组来说是正常的,所以如果你已经在考虑那么使用它们也许这会适合你。另一个麻烦是预先计算S
结构的总大小(包括s[]
任何填充)......