我想從浮點中提取位而不調用未定義的行爲。這是我的第一次嘗試:浮點數和嚴格的別名
unsigned foo(float x)
{
unsigned* u = (unsigned*)&x;
return *u;
}
據我所知,這是不能保證工作,由於嚴格的別名規則,對吧?如果使用字符指針進行中間步驟,它會工作嗎?
unsigned bar(float x)
{
char* c = (char*)&x;
unsigned* u = (unsigned*)c;
return *u;
}
或者我必須自己提取單個字節嗎?
unsigned baz(float x)
{
unsigned char* c = (unsigned char*)&x;
return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
當然這具有取決於字節順序的缺點,但我可以忍受這一點。
工會黑客絕對是未定義的行爲,對吧?
unsigned uni(float x)
{
union { float f; unsigned u; };
f = x;
return u;
}
爲了完整起見,這裏是foo
的參考版本。還有未定義的行爲,對吧?
unsigned ref(float x)
{
return (unsigned&)x;
}
所以,是有可能的位從一個浮提取物(假設兩個32個位寬的,當然)?
編輯:這裏是由Goz提出的memcpy
版本。由於許多編譯器不支持static_assert
的是,我已經取代static_assert
一些模板元編程:
template <bool, typename T>
struct requirement;
template <typename T>
struct requirement<true, T>
{
typedef T type;
};
unsigned bits(float x)
{
requirement<sizeof(unsigned)==sizeof(float), unsigned>::type u;
memcpy(&u, &x, sizeof u);
return u;
}
我真的沒有看到一個問題的第一個方法 - 你甚至不用指向同一個對象的兩個指針。你應該沒問題,儘管你可能需要一個編譯時斷言sizeof(float)== sizeof(unsigned)。我也沒有看到聯盟黑客的問題(雖然我會再次驗證大小)。但我確信有一些我不知道的晦澀難懂的規則。讓我們坐下來等待人們證明我錯了! – EboMike 2010-12-01 19:45:58
@Eomom:第一種方法違反了嚴格的鋸齒規則。閱讀這篇文章:http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html – Goz 2010-12-01 19:47:17
謝謝,我知道有人會證明我錯了:) – EboMike 2010-12-01 19:48:15