我最近通过组合三元运算符遇到了一个棘手/有趣的问题 通过位域访问,代码已经简化到足以暴露问题。
#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 也是未定义的,但我不太记得是否允许 union 为其事件成员的类型起别名,因此它可能定义得非常好(无论您的代码如何工作是一个有效的结果)。
鉴于此,尝试猜测为什么具有一组编译器选项和一组标准库的编译器在一个特定的硬件上可能会选择一组特定的未定义没有多大意义实现行为。
关于c++ - 三元运算中的位域作为左值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25633235/