这是如何使用C struct hack时分配的“额外”内存?
问题:
我在下面有一个C struct hack实现。我的问题是如何使用我分配给hack的“额外”内存。有人可以给我一个使用额外内存的例子吗?
#include<stdio.h>
#include<stdlib.h>
int main()
{
struct mystruct {
int len;
char chararray[1];
};
struct mystruct *ptr = malloc(sizeof(struct mystruct) + 10 - 1);
ptr->len=10;
ptr->chararray[0] = 'a';
ptr->chararray[1] = 'b';
ptr->chararray[2] = 'c';
ptr->chararray[3] = 'd';
ptr->chararray[4] = 'e';
ptr->chararray[5] = 'f';
ptr->chararray[6] = 'g';
ptr->chararray[7] = 'h';
ptr->chararray[8] = 'i';
ptr->chararray[9] = 'j';
}
答案 0 :(得分:15)
是的,这是({是})C
创建和处理大小不一的struct
的标准方法。
这个例子有点冗长。大多数程序员会更灵巧地处理它:
struct mystruct {
int len;
char chararray[1]; // some compilers would allow [0] here
};
char *msg = "abcdefghi";
int n = strlen (msg);
struct mystruct *ptr = malloc(sizeof(struct mystruct) + n + 1);
ptr->len = n;
strcpy (ptr->chararray, msg);
}
答案 1 :(得分:5)
自从我读到这篇文章(http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx)以来,我一直喜欢使用struct hack:
#include<stdio.h>
#include<stdlib.h>
int main()
{
struct mystruct {
int len;
char chararray[1];
};
int number_of_elements = 10;
struct mystruct *ptr = malloc(offsetof(struct mystruct, chararray[number_of_elements]));
ptr->len = number_of_elements;
for (i = 0; i < number_of_elements; ++i) {
ptr->chararray[i] = 'a' + i;
}
}
我发现不必记住1是否需要减去(或添加或其他)是好的。这也有在数组定义中使用0
的情况下工作的好处,并非所有编译器都支持,但有些支持。如果分配基于offsetof()
,则无需担心可能导致数学错误的详细信息。
它也可以不加改变,因为struct是C99灵活的数组成员。
答案 2 :(得分:1)
我建议不要因为可能的对齐问题而考虑这个:
struct my_struct
{
char *arr_space;
unsigned int len;
}
struct my_struct *ptr = malloc(sizeof(struct my_struct) + 10);
ptr->arr_space = ptr + 1;
ptr->len = 10;
这将为您提供局部性和安全性:)并避免奇怪的对齐问题。
通过对齐问题,我的意思是访问未对齐内存的访问延迟。
在原始示例中,如果添加一个字节或非字对齐的成员(byte,char,short),那么编译器可能会扩展结构的大小,但就指针而言,您正在读取内存后的内存。结构的结尾(未对齐)。这意味着如果您有一个对齐类型的数组,例如int
,那么每次访问都会使您在读取未对齐内存时触及命中的CPU上遇到性能损失。
struct
{
byte_size data;
char *var_len;
some_align added by compiler;
}
在原始情况下,您将从some_align
区域读取,这只是填充物,但在我的情况下,您将从之后读取对齐的额外内存(这浪费了一些空间,但这通常没问题)。
这样做的另一个好处是,通过在一次分配中为struct
的可变长度成员分配所有空间而不是单独分配它们,可以从分配中获得更多的局部性(避免多次分配)调用开销并给你一些缓存局部性而不是在整个内存中弹跳。)
答案 3 :(得分:1)
这是'正确的',但你需要一个很好的理由来做一个更合理的解决方案。更常见的是,您可能会使用此技术“覆盖”某些现有数组,以对其施加某种标头结构。
请注意,GCC的扩展允许zero length array member用于此目的,而ISO C99通过允许具有空括号的成员(仅作为最后一个成员)使该实践“合法化”。
请注意,存在一些语义问题 - 结构的大小当然不会占最终成员的“灵活”大小,并且“按值”传递结构只会传递标题和第一个元素(或者没有元素)使用GCC扩展或C99灵活阵列成员)。类似地,直接结构分配不会复制所有数据。