__uint128_t的reinterpret_cast
据我所知,reinterpret_cast 不得导致数据丢失。
因此不可能在 X86_64 中编译这样的代码,因为整数小于指针
#include <cstdio>
int main() {
int a = 123;
int res = reinterpret_cast<int>(reinterpret_cast<void*>(a));
printf("%d", a == res);
}
问题是:为什么我可以在 GCC 和 Clang 中编译这样的代码?
#include <cstdio>
int main() {
__uint128_t a = 4000000000000000000;
a *= 100;
__uint128_t res = reinterpret_cast<__uint128_t>(reinterpret_cast<void*>(a));
printf("%d", a == res);
}
我得到的结果是“0”,表示有数据丢失。
编辑
我认为有 3 种可能的变体。编译器错误、滥用规范或规范的后果。这是哪个?
回答
这里解释了https://en.cppreference.com/w/cpp/language/reinterpret_cast
- 指针可以转换为任何足够大的整数类型以保存其类型的所有值(例如到 std::uintptr_t)
这就是为什么你在第一种情况下有错误
- 任何整数或枚举类型的值都可以转换为指针类型...
这就是为什么您没有错误的原因,但在第二种情况下它会换行为 0。它以某种方式假设指针类型与任何整数类型相比具有最大的范围,而对于 128 位整数,情况并非如此。
请注意,一般来说 128 位整数不是整数类型,但至少 gcc 将其定义为 gcc 扩展中的:
来自https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/
libstdc++(在标准的非 gnu++XX 模式下)将 is_integral_v<__int128> 保留为 false。从库实现者的角度来看,这在一定程度上是有意义的,因为 __int128 不是标准的整数类型之一,而且,如果你称它为整数,那么你必须面对 intmax_t(它是 64 位的)每个重要的 ABI)都在说谎是“最大值”。
但
在 -std=gnu++XX 模式下,libstdc++ 使 is_integral_v<__int128> 变为 true
- @CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP Spec says any integer can be converted to a pointer, so it's a consequence of the spec.
-
Actually this part looks like a solution:
(the round-trip conversion in the opposite direction is not guaranteed; the same pointer may have multiple integer representations)
Which is a little bit confusing, I think it is a correct opinion that compiler devs assume that pointer type is the biggest.