2012-09-06 36 views
2
union 
{ 
    Uint32 Integer; 
    Float32 Real; 
} Field;  

我必須使用該聯合的一個小小的IEEE技巧,這是否打破嚴格的別名? GCC不拋出任何警告(與GCC 4.5,甚至與迂腐嚴格別名4.6,但據我所知,GCC不是很好捕嚴格別名規則infringiments(大量的誤報/陰性)嘗試。這個聯盟是否打破嚴格的別名?什麼是浮點寄存器

Field A; 
A.Integer = (Value1 & B) || Value2; 
return A.Real; 

這是我目前正在使用的代碼片段,它看起來沒有任何警告正常工作,但也許會有一些副作用或未定義的行爲,如果某些編譯器優化,那麼如果這段代碼可能是不安全的,我會使用一些努力去除它

另外,我假設這段代碼將需要將數據從標準寄存器移動到大多數現代CPU上的浮點指針寄存器(只是好奇的ABO ),涉及到一些額外的週期方面的老款CPU,是否正確?上面的代碼並不打算成爲一個優化,所以只是不要因爲濫用優化而減損我,上面的代碼是我獲得某個結果最簡單的方法(幸運的是,最簡單的方法似乎也是在我的情況下是最快的!),如果結果不安全,那麼我會用一個較慢的方法。

在此先感謝

回答

0

這是UB(但不要求嚴格的別名)。此外,union d數據總是通過實現AFAIK存儲在內存中,否則將需要知道源數據來自哪個寄存器,這意味着知道源類型。

1

通過聯合的別名在C中定義,但在C++中有未定義的行爲;未定義的行爲等同於從未初始化的變量(左值到右值轉換)讀取時發生的行爲。

因此,這種情況最容易中斷的方式是優化器決定從聯合中刪除讀取,因爲它沒有定義的值。但是,大多數C和C++編譯器可能會給你C的行爲,因爲他們需要支持。

別名值的安全方法是通過按字節複製例如std::memcpystd::copy(reinterpret_cast<char *>(...), ...)。或者,如果您可以用C和C++編譯項目,則可以將聯合別名代碼移動到C源文件,並將該代碼編譯爲C.

+0

您確定按位副本是標準編譯的嗎?從技術上講,你首先將'float'讀爲'char [4]'(這是OK),然後在RHS的內存位置寫入char [4],然後將'char [4]'別名爲' int'這是嚴格的別名規則所不允許的。 – Kos

+0

@Kos按字節順序複製到/ char數組在3.9p2中描述,並且在3.9p3中直接按字節複製,這樣就不會違反別名。有一點需要注意的是,該標準只涵蓋具有相同類型的源和目的地。 – ecatmur