联合中的对齐结构是否可以转换为联合以访问对齐的字段?

时间:2015-11-25 13:25:36

标签: c c99 strict-aliasing

我正试图弄清楚你从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中的动态分配,没有这样的事情。所以,如果你不能这样做,你可以用什么来做动态内存分配,例如上面这个例外?

2 个答案:

答案 0 :(得分:2)

如果FooBar具有不同的对齐方式,那么您不应仅仅因为这个原因而这样做。 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的函数的地方声明。