使用struct hack的结构数组

使用struct hack的结构数组,c,C,假设我在C中有这样的结构 struct A { int len; char s[1]; } 我希望有一个以上结构的数组,但是结构A的char s[1]成员可以是可变长度的。我们怎样才能做到这一点?甚至C99中的结构破解技巧在这里似乎也不起作用。一种解决方案是将char*作为最后一个成员并进行动态内存分配,但我希望struct的所有数据都位于相邻位置,因为我的实现需要不受缓存影响 您不能拥有可变大小对象的数组,因此不能使用struct hack拥有结构数组。数组中的所有对象必须具有相

假设我在C中有这样的结构

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

我希望有一个以上结构的数组,但是结构A的char s[1]成员可以是可变长度的。我们怎样才能做到这一点?甚至C99中的结构破解技巧在这里似乎也不起作用。一种解决方案是将char*作为最后一个成员并进行动态内存分配,但我希望struct的所有数据都位于相邻位置,因为我的实现需要不受缓存影响

您不能拥有可变大小对象的数组,因此不能使用struct hack拥有结构数组。数组中的所有对象必须具有相同的大小。如果它们都是相同的大小,那么大小必须由结构来暗示,因此您毕竟不会使用struct hack;在你的结构中,数组的维度中会有一个非1的大小,除非1对于所有东西都足够大。原因是a[i]的存储位置(其中a是数组的名称,i是数组的索引)必须可计算为“a的字节地址加i乘以数组中一个对象的大小”。因此,数组中对象的大小在这种情况下,结构必须已知并固定

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

请注意,C99取消了从未正式可移植的“struct hack”,尽管实际上是,它引入了“flexible array members”:

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

但是,上面的建议仍然适用。

您不能拥有可变大小对象的数组,因此您不能使用struct hack拥有结构数组。数组中的所有对象必须具有相同的大小。如果它们都是相同的大小,那么大小必须由结构来暗示,因此您毕竟不会使用struct hack;在你的结构中,数组的维度中会有一个非1的大小,除非1对于所有东西都足够大。原因是a[i]的存储位置(其中a是数组的名称,i是数组的索引)必须可计算为“a的字节地址加i乘以数组中一个对象的大小”。因此,数组中对象的大小在这种情况下,结构必须已知并固定

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

请注意,C99取消了从未正式可移植的“struct hack”,尽管实际上是,它引入了“flexible array members”:

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

但是,上面的建议仍然适用。

如果s有一个最大大小,您可以使用它而不是[1]。这使一切保持连续


如果您真的不想使用动态内存,那么就不能使用数组。您需要自己的管理器,它将对每个成员单独使用struct hack技巧-但这意味着您不能进行索引查找-您必须查看每个元素的大小,并将正确的字节数跳转到下一个元素。

如果s的大小有一个最大值,您可以使用它而不是[1]。这使一切保持连续


如果您真的不想使用动态内存,那么就不能使用数组。您需要自己的管理器对每个成员单独使用struct hack技巧-但这意味着您不能进行索引查找-您必须查看每个元素的大小,并将正确的字节数跳转到下一个元素。

在C中,数组索引涉及将基址乘以单个元素的编译时常量大小。因此,您不能直接将内置数组支持与struct hack一起使用,因为每个s元素都将被精确地分配到您请求的1字节,并且超过struct的索引将访问数组中的以下s元素,或者完全停止,可能会崩溃

如果你真的需要连续数据来提高缓存访问速度,你可以自己打包,你可以像大多数事情一样通过间接寻址来解决这个问题。。。拥有一个连续的S*数组,并手动将数据打包到另一个连续的缓冲区malloc或stack为所有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[]和前面的任何填充…

在C语言中,数组索引涉及将基址乘以单个元素的编译时常量大小。因此,您不能直接将内置数组支持与struct hack一起使用,因为每个s元素都将被精确地分配到您请求的1字节,并且超过struct的索引将访问数组中的以下s元素,或者完全停止,可能会崩溃

如果你真的需要连续数据来提高缓存访问速度,你可以自己打包,你可以像大多数事情一样通过间接寻址来解决这个问题。。。拥有一个连续的S*数组,并手动将数据打包到另一个连续的缓冲区malloc或stack为所有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[]和前面的任何填充…

如果它不能是struct数组,那么它将是指向struct的指针数组…正确;我已经澄清了我的答案,我希望强调为什么它必须如此。由于结构填充字节,它在实践中从来都不是可移植的。无论何时从具有类似体系结构的平台(如Windows和Linux之间)进行移植,它都可以正常工作。如果你从一个8位微控制器移植到Windows,你很可能会遇到问题,因为它们有完全不同的对齐要求;我已经澄清了我的答案,我希望强调为什么它必须如此。由于结构填充字节,它在实践中从来都不是可移植的。无论何时从具有类似体系结构的平台(如Windows和Linux之间)进行移植,它都可以正常工作。如果您将8位微控制器移植到Windows,您很可能会遇到问题,因为它们会有完全不同的对齐要求。我想到了这一点,我认为如果我没有得到更好的东西,我就必须这样做。我想到了这一点,我认为如果我没有得到更好的东西,我就必须这样做。这只是C99之前的一次黑客攻击,如果你在C90中这样做,任何事情都可能发生。在C99中,它是一个定义良好的特性,称为flexible array member。这只是C99之前的一个攻击,如果你在C90中这样做,任何事情都可能发生。在C99中,它是一个定义良好的特性,称为flexible array member。