C++ 联合:从联合的一个数据成员中读取数据以写入另一个

C++ 联合:从联合的一个数据成员中读取数据以写入另一个,c++,unions,strict-aliasing,C++,Unions,Strict Aliasing,我知道对于下面的代码,下面的“非法”是未定义的(虽然有些编译器允许),因为联合成员“a”处于活动状态,然后我们从联合成员“b”读取。 问题是,“AmILegal”中的代码是否修复了它,或者我是否在做一些可怕甚至更模糊的事情?我可以使用memcpy实现同样的效果吗?或者我在那里调用的是另一个未定义的行为吗 编辑:也许这个例子不够清楚。我只想激活另一个成员。 所以我将float改为int。虽然它看起来很愚蠢,但它更接近真实情况。阅读下面的代码 (是否出于某种原因不允许将一个工会成员复制到另一个工会成

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

编辑:也许这个例子不够清楚。我只想激活另一个成员。 所以我将float改为int。虽然它看起来很愚蠢,但它更接近真实情况。阅读下面的代码

(是否出于某种原因不允许将一个工会成员复制到另一个工会成员中?)

structfoo
{
联合酒吧
{
int a[4];
int b[4];
};
无效此\u是非法的()
{
a[0]=1;
a[1]=2;
a[2]=3;
a[3]=4;

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

老实说,我只会坚持第一条——这种行为在技术上还没有定义,但我怀疑它对你来说是正确的


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

this\u是非法的,this\u是合法的?这几乎是使用枚举的标准方式。)


但是memcpy不起作用,因为由于enum和memcpy不起任何作用,因此a和b在同一个地址

因为&a和&b在同一个地址,所以您可以对枚举执行一些有趣的操作-在您的例子中,将浮点解释为整数是枚举的内置功能,但无法触发自动强制转换,因为它们位于同一地址


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

未定义行为的问题在于,它可能在不同的编译器下,甚至在同一编译器的不同版本下,甚至在不同平台上的同一编译器的同一版本下,执行的方式不同。因此,仅仅因为它产生了所需的输出,不应该提倡或鼓励。你确定第三个是未定义的行为吗?我的意思是在浮点上写入任意字节?我已经做了我想做的,但我想让它具有1000%的可移植性和有效性。如果你将字节从一个有效浮点复制到另一个浮点,那么你就可以了,新的浮点具有相同的值就像旧的浮点一样。如果你写任意字节,那么所有的赌注都是无效的。(在新标准中是3.9/2-3。)“但是memcpy不会工作,因为由于enum和memcpy在同一个地址,memcpy不会做任何事情”-我知道它不需要做任何事情。我想做的就是确保第二个工会成员是活动的,所以它是“定义的”从中读取。它总是被定义的-枚举只在编译时存在,它提供对重叠内存空间的类型化访问,仅仅因为它是使用联合的正常方式并不意味着它是根据标准定义的。@ZoltánNagy你在谈论哪个枚举?你能发布相关的源代码吗?“所以我把float改为int。”我不明白你想做什么;你想把(
int
float
)的位模式解释为(
float
int
)?(这就是所谓的“类型双关”)伙计们,请阅读代码下面的最后一段。我正在解释真正的用例,但因为真正的代码使用的是VC++编译器intrinsics et.c。在这里使用它将是非常不可读的。该用例将一个u m128的内存位置返回为浮点[4](这几乎是它的定义),虽然确保定义了行为。但在您的示例中甚至没有一个
float
声明!有,但它只是让人们试图推断我想对float中的数据做什么,从而混淆了事情。我删除了它,因为数据类型与问题无关:我只想知道我问的问题:是否可以激活非-通过从另一个枚举成员写入来激活枚举成员。_m128是困扰我的具体情况,但我想要一个通用的答案。
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];
    }

};