2014-09-02 46 views
2

我最近 相結合的三元運營位域訪問時遇到一個棘手/有趣的問題,該代碼已被簡化足以暴露只是問題。位域三元操作作爲左值

#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 更新:代碼被再次編輯,真正把精力放在問題孤單。 (沒有了鑄造)

+0

我想你正在使用VC,究竟是什麼版本?我用你的代碼嘗試了gcc和clang,沒有崩潰,打印0,1,2。 – 2014-09-02 22:31:36

+0

看起來像(特別是你的第二次更新消除了可能的別名紅鯡魚),你已經發現了MSVC中的一個codegen錯誤。您應該在connect.microsoft.com上打開一個錯誤報告。 – 2014-09-03 01:34:00

+0

感謝您的精彩見解。票證已提交:https://connect.microsoft.com/VisualStudio/feedbackdetail/view/962553/codegen-bug-in-accessing-bitfield-in-ternary-operations-as-lvalue – user3788697 2014-09-03 05:10:25

回答

0

試試這個:

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

針對指定的C++布爾性質,甚至可以簡單地簡化爲:

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

這不是一個答案,它只會提供更多的信息。它應該是一個評論。 – 2014-09-02 23:48:10

1

版本1和3肯定違反嚴格別名規則,這是未定義的行爲。鑑於此,版本1在版本3失敗時工作肯定是一種可能未定義的行爲。

相信版本2也不確定的,但我也不太記得,如果工會允許別名的積極成員的類型,所以它可能是非常明確的(無論哪種方式,你的代碼的工作是有效的結果)。

鑑於此,試圖猜測爲什麼一個編譯器,一組編譯器選項和一組標準庫在一個特定硬件上可能會選擇一組特定的未定義的行爲來執行。

+1

實際上它與嚴格的別名規則無關,請嘗試下面的代碼:UnnamedUnion obj; (1 == 1?obj.BitField.Bit_0_1:obj.BitField.Bit_0_1)= 2;它仍然沒有相同的簽名。 – user3788697 2014-09-03 01:10:11