我正试图弄清楚你从C99中的对齐变量的缓和中获得了什么:
Exception to strict aliasing rule in C from 6.5.2.3 Structure and union members
如果原始写入是通过指向其中一个对齐结构的指针完成的,那么它是否会在转换为该联合时给予全权委托?
#include <stdio.h>
#include <stdlib.h>
struct Foo { char t; int i; };
struct Bar { char t; float f; };
union FooBar {
struct Foo foo;
struct Bar bar;
};
void detector(union FooBar *foobar) {
if (((struct Foo*)foobar)->t == 'F')
printf("Foo %d\n", ((struct Foo*)foobar)->i);
else
printf("Bar %f\n", ((struct Bar*)foobar)->f);
}
int main() {
struct Foo *foo = (struct Foo*)malloc(sizeof(struct Foo));
struct Bar *bar = (struct Bar*)malloc(sizeof(struct Bar));
foo->t = 'F';
foo->i = 1020;
detector((union FooBar*)foo);
bar->t = 'B';
bar->f = 3.04;
detector((union FooBar*)bar);
return 0;
}
请注意,在第二个调用中,t
被写为“bar's t”但是为了辨别它有哪种类型,检测器将其读作“ foo's t“
我对C ++的反应是,如果您“首先将其分配为FooBar联盟”,那么您只能做到这一点。我认为这是合法的,这对我来说是违反直觉的,但对于C中的动态分配,没有这样的事情。所以,如果你不能这样做,你可以用什么来做动态内存分配,例如上面这个例外?
答案 0 :(得分:2)
如果Foo
和Bar
具有不同的对齐方式,那么您不应仅仅因为这个原因而这样做。 union
将具有两者的最大对齐,并且使用较小的值投射一个将为您提供未正确对齐的union
。
您的代码不是别名规则的好例子,因为您基本上没有别名。但一般来说,在你可能有别名的情况下,对另一种类型的强制转换总是很糟糕。您的编译器可能会假设代码看到的两个(或更多)指针。如果它们的类型不同(char
类型除外),编译器可以假定它们从不指向同一个对象。
答案 1 :(得分:2)
如果你做了这样的事情:
struct Foo foo;
struct Bar bar;
...
detector((union FooBar*)&foo);
detector((union FooBar*)&bar);
然后你可能会遇到对齐问题,因为编译器可能会将这些结构中的每一个放在堆栈上,而这种结构可能无法正确对齐另一个。
但是因为在你的情况下,你为每个结构动态分配内存,所以对齐不是问题。
来自malloc
的手册页:
对于
calloc()
和malloc()
,返回的值是指向的值 分配内存,适合任何类型的内存 变量,如果请求失败,则为NULL。
但是如果你想确定这不会成为一个问题,只需声明一个union的实例,而不是在任何可能调用union的函数的地方声明。