三元运算中的位域作为左值

时间:2014-09-02 22:14:35

标签: c++

我最近通过组合三元运算符遇到了一个棘手/有趣的问题 通过位域访问,代码已经简化到足以暴露问题。

#include "stdafx.h"
#include <stdint.h>

typedef union
{
    struct 
    {
        uint32_t    Bit_0_1     : 2;
        uint32_t    Bit_2       : 1;
        uint32_t    Bit_3_To_31 : 29;
    } BitField;
    uint32_t RawValue;
} UnnamedUnion;

int _tmain(int argc, _TCHAR* argv[])
{
    UnnamedUnion a;
    UnnamedUnion b;
    a.RawValue = 0;
    b.RawValue = 0;
    //Version 1. Works
    if (1 == 1)
    {
        a.BitField.Bit_0_1 = 0;
    }
    else
    {
        b.BitField.Bit_0_1 = 0;
    }
    printf("Reg value : %u\n", a.RawValue);
    //Version 2. Also works
    (1 == 1 ? a.RawValue : b.RawValue) = 1;
    printf("Reg value : %u\n", a.RawValue);
    //Version 3. Crashes!
    (1 == 1 ? a.BitField.Bit_0_1 : b.BitField.Bit_0_1) = 2;
    printf("Reg value : %u\n", a.RawValue);

    getchar();
    return 0;
}

请注意,版本1,2,3都是等效表达式。我有关于这个的假设 因为我从未在编译器上工作过,但想听听大家的想法!
更新:确认在VS 2012和VS中都失败了2013年 更新:代码再次被编辑,真正专注于问题。 (不再施法)

2 个答案:

答案 0 :(得分:1)

版本1和3肯定违反了严格别名规则,这是未定义的行为。鉴于此,版本1工作而版本3失败肯定是一种可能的未定义行为。

相信版本2也是未定义的,但我不记得是否允许联盟为其活动成员的类型设置别名,因此它可能是完全明确定义的(无论你的代码是什么工作方式)是一个有效的结果。)

鉴于此,尝试猜测为什么在一个特定硬件上的一个编译器(带有一组编译器选项和一组标准库)可能会选择一个特定的未定义集合是没有多大意义的。要实施的行为。

答案 1 :(得分:0)

尝试一下:

reinterpret_cast<UnnamedUnion&>(someArray[(1==1)?0:1]).RawValue = 1;

考虑到C++布尔的性质,甚至可以简化为:

reinterpret_cast<UnnamedUnion&>(someArray[(1!=1)]).RawValue = 1;