将 int32 转换为 uint32 是空操作吗?

Ann*_*inn 4 c++ int casting type-conversion

我想int32_tuint32_t没有任何转换的情况下将an 的位粘贴到类型中,只是重新解释。以下代码正是我想要的:

int32_t  iA = -1;
uint32_t uA = *(uint32_t*)&iA;
Run Code Online (Sandbox Code Playgroud)

但我想知道,我可以依靠以下更容易编写的演员表来生成相同(或更少)的程序集,理想情况下只是movs?(即,它永远不会对其进行“数学运算”,而不会触及底层位。)

int32_t  iB = -1;
uint32_t uB = (uint32_t)iB;

assert(uA == uB); // ?
Run Code Online (Sandbox Code Playgroud)

Evg*_*Evg 7

在 C++20 之前,有符号整数的表示是实现定义的。但是,即使在 C++20 之前,std::intX_t保证有 2s'-补码表示:

int8_t, int16_t, int32_t, int64_t- 宽度分别为 8、16、32 和 64 位的有符号整数类型,没有填充位,对负值使用 2 的补码(仅当实现直接支持该类型时才提供)

当你写

std::int32_t  iA = -1;
std::uint32_t uA = *(std::uint32_t*)&iA;
Run Code Online (Sandbox Code Playgroud)

你得到所有位设置的值。该标准表示,如果“类型类似于......一种类型,该类型是与对象的动态类型相对应的有符号或无符号类型” std::int32_tstd::uint32_t*则允许通过类型指针进行访问。因此,严格来说,在取消引用指针之前,我们必须确保它std::uint32_t确实是一个对应的无符号类型std::int32_t

static_assert(std::is_same_v<std::make_unsigned_t<std::int32_t>, std::uint32_t>);
Run Code Online (Sandbox Code Playgroud)

当你写

std::int32_t  iB = -1;
std::uint32_t uB = (std::uint32_t)iB;
Run Code Online (Sandbox Code Playgroud)

您依赖于转换为定义明确并保证产生相同值的无符号类型。

至于程序集,两个演员都没有操作:

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;
}
Run Code Online (Sandbox Code Playgroud)

结果

foo():
        mov     eax, -1
        ret
bar():
        mov     eax, -1
        ret
Run Code Online (Sandbox Code Playgroud)