我的目标是这样的:
void alloc(*x)
{
x->ptr = malloc(100);
}
int main()
{
struct { int z; int *ptr; } foo;
struct { int z; double *ptr; } bar;
alloc(&foo);
alloc(&bar);
return 0;
}
函数alloc
应为不同类型的结构分配内存,这些结构基本相同,但使用不同的指针。
我尝试解决方案的方式如下:
struct generic {
int z;
void *ptr;
};
void alloc(void *x)
{
struct generic *tmp = x;
tmp->ptr = malloc(100);
}
或:
union generic {
void *p;
struct {
int z;
void *ptr;
} *g;
};
void alloc(void *x)
{
union generic tmp = {.p = x};
tmp.g->ptr = malloc(100);
}
它们是否正确或是否违反严格别名,因为实际参数与generic
不兼容 - 结构和解除引用x
或tmp.g
无效?
进一步,认为这违反了严格别名,它会产生什么影响?
严格别名用于不重新加载特定值,假设它们在没有以正确方式别名(char *,void *,union,兼容类型)时无法被修改。
使用void-pointer作为参数调用alloc()
,该参数可能是别名,因此调用者不能假定基础数据不会更改。在alloc()
内部,我将专门使用类型惩罚指针。那么在这种情况下,如果没有正确重新加载会出现问题呢?
答案 0 :(得分:2)
您可以将第二个成员放在结构中(以避免指针兼容性问题)。
C99 6.2.5.26
所有指向结构类型的指针都应具有相同的表示和对齐要求。
然后你可以使用union来进行类型惩罚(以避免严格的别名问题)。
struct generic
{
int z;
union
{
struct {int i;} i;
struct {double d;} d;
} *ptr;
};
void alloc(struct generic *x)
{
x->ptr = malloc(100);
}
int main(void)
{
struct generic foo;
struct generic bar;
alloc(&foo);
alloc(&bar);
return 0;
}
您不得不访问结构的成员。如果您使用gcc或任何与C11兼容的编译器,则可以使用匿名(未命名)结构成员绕过该问题。
似乎没有办法在符合要求的实施方式下工作。
答案 1 :(得分:0)
这两个代码段都不是便携式的。
至于第一个,tmp
的类型与x
指向的对象的类型不兼容,即struct { int z; int *ptr; }
或struct { int z; double *ptr; }
。因此,取消引用tmp
违反了严格的别名规则。
第二个片段的问题是,指针与不兼容类型的联合只会告诉编译器指针本身是别名的,而不是它们指向的对象,因此它仍然会破坏严格的别名(有关严格的更多信息)别名,请参阅here)。
两个片段忽略的是,不同类型的指针实际上可以具有不同的内部表示(尽管很少见),这就是为什么对双指针进行类型化处理,然后再将它用作双指针再次导致指针的位模式简单地重新解释,但没有转换,可能产生陷阱表示,因此产生无效指针(有关内部指针表示的更多信息,请参阅here)。
总之,两个片段的整体方法都不可移植,需要重新考虑。