在C++20之前,有符号整数的表示是实现定义的。但是,std::intX_t
在C++20之前也被保证具有2s'补码表示:
int8_t
、int16_t
、int32_t
和int64_t
- 分别为宽度恰好为8、16、32和64位的有符号整数类型,不含填充位,并使用2's补码表示负值(仅在实现直接支持该类型时提供)
当您编写以下代码时:
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;
}
result in:
foo():
mov eax, -1
ret
bar():
mov eax, -1
ret
memcpy
,它保证不改变任何位。 - alainuint32 uA = *(uint32*)&iA;
像这样的类型转换在C++中几乎总是未定义的行为 - 虽然我对这种情况并不完全确定。无论如何,除非您确信并且已经仔细检查了语言或编译器明确允许这样做,否则根本不要考虑这样做。另一方面,将基本类型强制转换始终是安全的,尽管我建议使用static_cast
。毕竟这不是C。 - besc