尝试使用一个malloc()ed块来存储多个不同类型的结构。成员虚构用于演示目的。不能对它们的类型,顺序等做出任何假设,除非它们构成完全合法的C结构(完全为C编译器所知并为C编译器定义)。这一次,其他时间就是这样。我追求这个概念。创建自己的混合,但想法必须相同 - header struct有指向其他结构的指针:
typedef struct
{
int a;
} s1_t;
typedef struct
{
int b;
} s2_t;
typedef struct
{
int c;
} s3_t;
typedef struct
{
s1_t* s1;
s2_t* s2;
s3_t* s3;
} hdr_t;
int
main( int argc, char* argv[] )
{
void* mem = malloc( sizeof( hdr_t ) +
sizeof( s1_t ) +
sizeof( s2_t ) +
sizeof( s3_t ) );
hdr_t hdr = ( hdr_t* )mem;
hdr->s1 = (s1_t* ) ( hdr + sizeof( hdr ) );
hdr->s2 = (s2_t* ) ( hdr->s1 + sizeof( s1_t ) );
hdr->s3 = (s3_t* ) ( hdr->s2 + sizeof( s2_t ) );
/* etc. */
}
上面(天真)代码是希望不用小mallocs对堆进行分段,而是为整个(在键盘时间已知)集合获取一个块。
问题:对于尽可能便携的解决方案,我是否必须在我的方案中手动对齐结构?
换句话说,我需要(伪代码),ALSZ =此芯片的对齐大小:
mem = malloc( hdrsz + ALSZ + s1sz + ALSZ + s2sz + ALSZ + s3sz );
hdr = ( hdr_t* )hdr;
s1 = align( hdr + sizeof( hdr_t ), ALSZ );
s2 = align( s1 + sizeof( s1 ), ALSZ );
s3 = align( s2 + sizeof( s2 ), ALSZ );
align(mem,boundary)是我计算对齐地址的例程。
感谢您的想法。
答案 0 :(得分:2)
而不是使用
typedef struct
{
s1_t* s1;
s2_t* s2;
s3_t* s3;
} hdr_t;
使用
typedef struct
{
s1_t s1;
s2_t s2;
s3_t s3;
} hdr_t;
main( int argc, char* argv[] )
{
void* mem = malloc( sizeof( hdr_t ));
hdr_t* hdr = ( hdr_t* )mem;
}
这实现了您正在寻找的内容:为一组结构连续分配内存,并保证hdr_t
的成员指向正确的位置而不用担心芯片内存对齐填充; < / p>
答案 1 :(得分:0)
Dancrumb的解决方案绝对是最好的,如果你可以使用它。如果不是(例如,如果您需要的结构数量是可变的,或者组合太多或特殊套管的成本过高),您可以自己进行校准:
由于任何类型的对齐要求总是除以类型的大小,因此首先采用可能出现在结构中的所有类型的LCM。如果您想要懒惰,只需将产品sizeof(short)*sizeof(int)*sizeof(long)*...
用于所有类型。或者只使用像64这样的两个大功率,你确定它们大于任何一个的大小。
然后,当对malloc获得的块进行指针运算时,将每个结构的大小向上舍入到您在上面选择的对齐值的下一个倍数。例如
#define ROUND_UP(n, a) (((n)+((a)-1))/(a)*(a))
ps2 = (void *) ( (char *)ps1 + ROUND_UP(sizeof(*ps1), ALIGNMENT) );
其中ps1
是指向malloc'd块中第一个结构的指针,ps2
是指向第二个结构的指针。
当然,在进行分配时需要进行相同的舍入,以确保有足够的空间。
编辑:我在一个旧答案中找到了改进。因为尝试找出最大可能的对齐要求是很痛苦的,特别是如果你想要100%便携,只需使用任何类型(包括结构)的对齐要求必须划分的事实类型的大小,并假设它们是相等的。那就是:
ps2 = (void *) ( (char *)ps1 + ROUND_UP(sizeof(*ps1), sizeof(*ps2)) );
将第一个结构的大小向上舍入到第二个结构大小的下一个倍数。这可能有点浪费,但它很简单,应该始终有效。
答案 2 :(得分:0)
您的指针算法有问题。向指针添加1不会使其前进一个字节,而是向下一个元素前进;按尖头大小。
如果你有
struct foo {
...
};
struct bar {
...
};
struct baz {
...
};
struct header {
...
struct foo *foo;
struct bar *bar;
struct baz *baz;
...
};
您可以使用
使用单个内存块分配结构struct header *ptr;
ptr = malloc (sizeof (struct header) + sizeof (struct foo) + sizeof (struct bar) + sizeof (struct baz));
if (!ptr) {
/* out of memory */
exit(1);
}
ptr->foo = (struct foo *)(ptr + 1);
ptr->bar = (struct bar *)(ptr->foo + 1);
ptr->baz = (struct baz *)(ptr->bar + 1);
或者,如果您希望使用字节偏移(例如,如果结构的大小是动态的 - 在C99中非常合法),则可以使用
struct header *ptr;
char *tmp;
tmp = malloc (sizeof (struct header) + sizeof (struct foo) + sizeof (struct bar) + sizeof (struct baz));
if (!tmp) {
/* out of memory */
exit(1);
}
ptr = (struct header *)tmp;
ptr->foo = (struct foo *)(tmp + sizeof (struct header));
ptr->bar = (struct bar *)(tmp + sizeof (struct header) + sizeof (struct foo));
ptr->baz = (struct baz *)(tmp + sizeof (struct header) + sizeof (struct foo) + sizeof (struct bar));
在这两种情况下,struct header
结构中的指针将获得相对于struct header
本身指针的相同值。在后一种情况下,如果使用任意结构大小,还必须记住按ABI要求对齐新指针。