首页 > 解决方案 > 将 int32 转换为 uint32 是无操作的吗?

问题描述

我想在没有任何转换的情况下将 a 的位int32_t插入到类型uint32_t中,只是重新解释。以下代码正是我想要的:

int32_t  iA = -1;
uint32_t uA = *(uint32_t*)&iA;

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

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

assert(uA == uB); // ?

标签: c++castingtype-conversionint

解决方案


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

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;

你得到所有位设置的值。该标准规定如果“类型类似于...一种类型,该类型是与对象的动态类型相对应的有符号或无符号类型”,则允许std::int32_t通过类型指针进行访问。因此,严格来说,在取消引用指针之前std::uint32_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

推荐阅读