我最近通过组合三元运算符遇到了一个棘手/有趣的问题 通过位域访问,代码已经简化到足以暴露问题。
#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年
更新:代码再次被编辑,真正专注于问题。 (不再施法)
答案 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;