我有一些struct
这样:
struct myStruct0 {
void(*deallocMe)(void*); // points always to "myStruct0_dealloc"
uint8_t* someStuff;
void* someOtherStuff;
}
void myStruct0_dealloc(void* structPtr) {
myStruct0* s = (myStruct0*)structPtr;
free(s->someStuff);
free(s->someOtherStuff);
free(s);
}
struct myStruct1 {
void(*deallocMe)(void*); // points always to "myStruct1_dealloc"
uint8_t* someStuff;
uint64_t largeArray[4096];
void* someOtherStuff;
char* someRealOtherStuff;
}
void myStruct1_dealloc(void* structPtr) {
myStruct1* s = (myStruct1*)structPtr;
free(s->someStuff);
free(s->someOtherStuff);
free(s->someRealOtherStuff);
free(s);
}
struct
和指针都使用malloc分配(当然不能为NULL)。
以下代码是否安全?
struct genericForm {
void(*deallocMe)(void*);
}
void deallocMyStructX(void* myStructX) {
genericForm* x = (genericForm*)myStructX;
x->deallocMe(myStructX);
}
为什么我要这样做?
我将有一些指向某些struct
的指针,如上所述,如果这样可行,我不必为每个struct
/指针保存解除分配器。这样可以简化我的代码。
编辑:
结构可以完全不同。他们唯一共享的是它们包含一个void(*)(void*)
形式的函数指针作为第一个元素。
答案 0 :(得分:5)
如果您只想访问结构的第一个成员,那么您应该没问题。第一个成员的偏移量保证为0,如果第一个成员与所有结构(即函数指针)兼容,那么你应该没问题。如果您要取消引用结构并访问其他成员,则可能会因填充而遇到问题。添加占位符成员可能会解决这个问题,但可能有点效率低下。
如果你没有太多的结构要担心,这可能是一个更容易的解决方案:
struct _data {
int identifier;
union {
struct type_1 {} _t1;
struct type_2 {} _t2;
struct _generic {
void (*dealloc_generic)(void *);//first member is dealloc function pointer
} _gen;
};
};
void dealloc_struct(struct _data * s)
{
switch (s->identifier)
{
case 1:
s->t1->delloc_t1_ptr(s->t1);
return;
//and so on
default:
//for generic-compatible structs
s->_gen->delloc_generic(s->_gen);
}
}
如果你的结构的第一个成员总是一个有效的函数指针,那么你甚至可以这样写:
void dealloc_struct(void *s)
{
//cast s to function pointer, call it and pass the pointer as argument
((void (*)(void *))s)(s);
}
根据标准(C1x§6.7.2.1.13),这应该有效:
指向适当转换的结构对象的指针指向其初始成员[...],反之亦然。在结构对象中可能有未命名的填充,但不在其开头。
答案 1 :(得分:1)
在C中允许/安全使用不同大小的结构?
一般来说:没有。一个结构的寻址空间可能与另一个结构完全不兼容。
解决方案是将两个结构放在union
。
struct myStruct0 {
void(*deallocMe)(void*); //Common elements must be in the beginning with same type/order
...
}
struct myStruct1 {
void(*deallocMe)(void*);
...
}
union genericForm {
struct myStruct0 s0;
struct myStruct1 s1;
}
使用迂腐方法
struct myStruct0 {
...
};
struct myStruct1 {
...
};
struct genericForm {
void(*deallocMe)(void*); //Common elements here
union { // Anonymous union
struct myStruct0 s0;
struct myStruct1 s1;
};
};