[英]Is casting int32 to uint32 a no-op?
我想將int32_t
的位粘貼到uint32_t
類型中而不進行任何轉換,只是重新解釋。 以下代碼正是我想要的:
int32_t iA = -1;
uint32_t uA = *(uint32_t*)&iA;
但我想知道,我可以依靠以下更容易編寫的演員表來生成相同(或更少)的程序集,理想情況下只是mov
s? (即,它永遠不會對其進行“數學運算”,而不會觸及底層位。)
int32_t iB = -1;
uint32_t uB = (uint32_t)iB;
assert(uA == uB); // ?
在 C++20 之前,有符號整數的表示是實現定義的。 但是,即使在 C++20 之前, std::intX_t
也保證具有 2s' 補碼表示:
int8_t
、int16_t
、int32_t
、int64_t
- 帶符號整數類型,寬度分別為int16_t
和 64 位,沒有填充位,對負值使用 2 的補碼(僅當實現直接支持該類型時才提供)
當你寫
std::int32_t iA = -1;
std::uint32_t uA = *(std::uint32_t*)&iA;
你得到所有位設置的值。 該標准表示,如果“類型類似於......一種類型,該類型是與對象的動態類型相對應的有符號或無符號類型”,則允許通過類型為std::uint32_t*
的指針訪問std::int32_t
。 因此,嚴格來說,在取消引用指針之前,我們必須確保std::uint32_t
確實是對應於std::int32_t
的無符號類型:
static_assert(std::is_same_v<std::make_unsigned_t<std::int32_t>, std::uint32_t>);
當你寫
std::int32_t iB = -1;
std::uint32_t uB = (std::uint32_t)iB;
您依賴於轉換為定義明確並保證產生相同值的無符號類型。
至於程序集,兩個演員都沒有操作:
std::uint32_t foo() {
std::int32_t iA = -1;
static_assert(std::is_same_v<std::make_unsigned_t<std::int32_t>, std::uint32_t>);
return *(std::uint32_t*)&iA;
}
std::uint32_t bar() {
std::int32_t iB = -1;
return (std::uint32_t)iB;
}
結果:
foo():
mov eax, -1
ret
bar():
mov eax, -1
ret
使用memcpy
是避免在別名類型時出現未定義行為的常見解決方案。 評論中指出,僅在符號上不同的別名類型是可以的,但例如float
和int
就不是這種情況。
只要對象表示對該類型有效, memcpy
可以工作。
編譯器非常擅長優化memcpy
調用,在這種情況下,調用完全被優化掉了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.