我希望将int32_t
的位粘贴到类型uint32_t
中,而无需进行任何转换,而只是重新解释。以下代码正是我想要的:
int32_t iA = -1;
uint32_t uA = *(uint32_t*)&iA;
但是我想知道,我是否可以依靠下面的代码来更容易地编写强制转换,以生成相同(或更少)的程序集,最好是mov
? (即,它将永远不会对其进行“数学运算”,而使基础位保持不变。)
int32_t iB = -1;
uint32_t uB = (uint32_t)iB;
assert(uA == uB); // ?
答案 0 :(得分:7)
直到C ++ 20,带符号整数的表示形式是实现定义的。但是,std::intX_t
是order,即使在C ++ 20之前也具有2'补码表示:
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*
的标准guaranteed物体”。因此,严格来说,在取消引用指针之前,我们必须确保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;
您依靠转换为says的无符号类型并保证产生相同的值。
至于组装,两个演员都是无人操作:
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
答案 1 :(得分:3)
使用memcpy
是避免别名类型时出现未定义行为的常见解决方案。
在评论中指出,仅在签名上有所不同的别名类型是可以的,但是对于float
和int
来说不是这种情况。
memcpy
只要对象表示形式对该类型有效即可。
编译器非常擅长优化memcpy
调用,在本例中为the call is completely optimized away。