簡體   English   中英

將 int32 轉換為 uint32 是空操作嗎?

[英]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_tint16_tint32_tint64_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是避免在別名類型時出現未定義行為的常見解決方案。 評論中指出,僅在符號上不同的別名類型是可以的,但例如floatint就不是這種情況。

只要對象表示對該類型有效, memcpy可以工作。

編譯器非常擅長優化memcpy調用,在這種情況下,調用完全被優化掉了

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM