1

我知道对于下面的代码,下面的“非法”是未定义的(虽然一些编译器允许它),因为联合成员“a”是活动的,然后我们从联合成员“b”中读取。问题是,“AmILegal”中的代码是否修复了它,还是我在做一些可怕甚至更晦涩的事情?我可以使用 memcpy 来实现相同的效果,还是我在那里调用了另一个未定义的行为?

编辑:也许这个例子不够清楚。我想做的就是激活另一个成员。所以我将浮点数更改为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 实际上是一个与 float[4] 结合的 _m128。位表示始终是准确和正确的。在某个时间点,您将需要实际使用它,并且您需要将它作为浮点数组放在主内存中。“复制指令”实际上是从 _m128 联合成员到 float[4] 成员的 _mm_store_ps。因此,关于 memset 的问题 - 也许这是我需要的更准确的例子......

4

2 回答 2

0

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

老实说,我会坚持第一个 - 行为在技术上是未定义的,但我怀疑它只是为你做正确的事情。

第三个将一种形式的未定义行为切换为另一种形式(一旦您将任意字节写入浮点数,任何事情都可能发生)。但是,如果您知道字节确实代表了一个有效的浮点值,那就没问题了。

于 2012-07-15T09:13:15.710 回答
-1

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

但是 memcpy 不起作用,因为 &a 和 &b 由于枚举而位于同一个地址,而 memcpy 什么也不做

因为 &a 和 &b 在同一个地址,你可以用枚举做一些有趣的事情——在你的情况下,将浮点数解释为整数是枚举的内置功能,但不能触发自动转换,因为它们是在同一个地址

您可能想查看属性((packed)) 因为它有助于声明协议结构/枚举

于 2012-07-15T09:20:31.037 回答