__uint128_t 的 reinterpret_cast

CPP*_*CPP 1 c++ gcc clang

据我所知,reinterpret_cast 不得导致数据丢失。

因此不可能在 X86_64 中编译这样的代码,因为整数小于指针

#include <cstdio>
int main() {
    int a = 123;
    int res = reinterpret_cast<int>(reinterpret_cast<void*>(a));
    printf("%d", a == res);
}
Run Code Online (Sandbox Code Playgroud)

问题是:为什么我可以在 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);
}
Run Code Online (Sandbox Code Playgroud)

我得到的结果是“0”,表示有数据丢失。

编辑

我认为有 3 种可能的变体。编译器错误、滥用规范或规范的后果。这是哪个?

Jea*_*bre 6

这里解释了https://en.cppreference.com/w/cpp/language/reinterpret_cast

  1. 指针可以转换为任何足够大的整数类型以保存其类型的所有值(例如到 std::uintptr_t)

这就是为什么你在第一种情况下有错误

  1. 任何整数或枚举类型的值都可以转换为指针类型...

这就是为什么您没有错误的原因,但在第二种情况下它会换行为 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 规范表示任何整数都可以转换为指针,因此这是规范的结果。 (4认同)
  • 实际上这部分看起来像一个解决方案:(不能保证相反方向的往返转换;同一个指针可能有多个整数表示)这有点令人困惑,我认为编译器开发人员假设这是一个正确的观点指针类型最大。 (2认同)