联盟:从联盟的一个数据成员读取到另一个联盟

时间:2012-07-15 09:04:34

标签: c++ unions strict-aliasing

我知道对于下面的代码,下面的“Illegal”是未定义的(虽然有些编译器允许),因为union成员“a”是活动的,然后我们从union成员“b”读取。 问题是,“AmILegal”中的代码是否解决了这个问题,还是我做了一些可怕而且更加模糊的事情?我可以使用memcpy来实现相同的效果,还是我在那里调用了另一个未定义的行为?

编辑:也许这个例子不够明确。我想做的就是激活其他成员。 所以我将float更改为int。虽然看起来很蠢,但它更接近真实案例。阅读以下代码。

(由于某些原因,不允许将一个工会成员复制到另一个工会成员吗?)

struct Foo
{
    union Bar
    {
        int a[4];
        int b[4];
    };

    void this_is_Illegal()
    {
         a[0]=1;
         a[1]=2;
         a[2]=3;
         a[3]=4;
         std::cout<<b[0]<<b[1]<<b[2]<<b[3];
    }

    void but_is_this_Legal?()
    {
         a[0]=1;
         a[1]=2;
         a[2]=3;
         a[3]=4;

         b[0]=a[0];
         b[1]=a[1];
         b[2]=a[2];
         b[3]=a[3];
         std::cout<<b[0]<<b[1]<<b[2]<<b[3];
    }


    void this_looks_scary_but_is_it?()
    {
         a[0]=1;
         a[1]=2;
         a[2]=3;
         a[3]=4;
         //forget portability for this q, assume sizeof(int)==sizeof(float)
         //maybe memmove works here as well?
         memcpy(b, a, sizeof(int)*4)

         std::cout<<b[0]<<b[1]<<b[2]<<b[3];
    }

};

如果上述所有内容听起来都不是很有用,那么认为a实际上是_m128与float [4]结合在一起。位表示是完全正确的。 在某个时间点,您将需要实际使用它,并且您需要将它作为浮动数组存储在主存储器中。 “复制指令”实际上是从_m128联合成员到float [4]成员的_mm_store_ps。因此关于memset的问题 - 也许它是我需要的更准确的例子......

2 个答案:

答案 0 :(得分:0)

第二个函数是完全合法的 - 但不会做同样的事情,因为它将执行int到float转换而不是保持位不变。

说实话,我会坚持使用第一个 - 这种行为在技术上是未定义的,但我怀疑它对你来说是正确的。

第三种方法为另一种形式切换一种未定义的行为(一旦你将任意字节写入浮点数,就会发生任何事情)。但是如果你知道这些字节确实代表了一个有效的浮点值,那就没关系了。

答案 1 :(得分:-1)

this_is_illegal,this_is_legal?几乎是使用枚举的标准方法;)

但memcpy不起作用,因为enum和memcpy将无效,因此&amp; a和&amp; b处于同一地址

因为&amp; a和&amp; b在同一个地址你可以用enum做一些有趣的东西 - 在你的情况下,将一个浮点解释为整数是你的枚举的内置功能,但是自动转换可以'被触发,因为它们位于同一地址

您可能希望查看属性((压缩)),因为它有助于声明协议结构/枚举