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

#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和2013中均失败
更新:再次对代码进行了编辑,使其仅专注于该问题。 (不再投放)

最佳答案

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

我相信版本2也是未定义的,但我不太记得是否允许工会为 Activity 成员的类型加上别名,因此它可能是定义良好的(无论哪种方式,您的代码都是有效的结果)。

鉴于此,试图猜测为什么在一个特定硬件上一个编译器具有一组编译器选项和一组标准库并没有多大意义,所以可以选择在一组特定硬件上选择一组特定的未定义行为来实现。

关于c++ - 三元运算中的位域作为左值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25633235/

10-11 20:19