【发布时间】:2025-12-27 06:55:07
【问题描述】:
假设我有以下示例:
struct Dummy {
uint64_t m{0llu};
template < class T > static uint64_t UniqueID() noexcept {
static const uint64_t uid = 0xBEA57;
return reinterpret_cast< uint64_t >(&uid);
}
template < class T > static uint64_t BuildID() noexcept {
static const uint64_t id = UniqueID< T >()
// dummy bits for the sake of example (whole last byte is used)
| (1llu << 60llu) | (1llu << 61llu) | (1llu << 63llu);
return id;
}
// Copy bits 48 through 55 over to bits 56 through 63 to keep canonical form.
uint64_t GetUID() const noexcept {
return ((m & ~(0xFFllu << 56llu)) | ((m & (0xFFllu << 48llu)) << 8llu));
}
uint64_t GetPayload() const noexcept {
return *reinterpret_cast< uint64_t * >(GetUID());
}
};
template < class T > inline Dummy DummyID() noexcept {
return Dummy{Dummy::BuildID< T >()};
}
非常清楚结果指针是程序中静态变量的地址。
当我调用GetUID() 时,我是否需要确保第 47 位重复到第 63 位?
或者我可以只使用低 48 位掩码进行 AND 并忽略此规则。
我无法找到有关此的任何信息。我假设这 16 位可能总是0。
此示例严格限于 x86_64 架构 (x32)。
【问题讨论】:
-
这段代码应该做什么?什么是“规范形式”?
-
AMD 64 位体系结构指针中的一条规则,其中第 48 位到 63 位必须是第 47 位的副本。更多信息请参阅en.wikipedia.org/wiki/X86-64#Virtual_address_space_details@ 64 位中只有 48 位被指针使用(现在)。因此,理论上您可以使用最后 16 位将其他信息与指针相关联。假设您在尝试访问该地址之前会丢弃该信息。
-
至于代码应该做什么。在这个例子中什么都没有。但对于我的用例。它应该充当轻量级 RTTI 替代品。没有继承,没有复杂的东西。只是想成为一个类似于
std::type_info的结构,而不是0xBEA57,它将是一个指向包含有关类型(包括名称)的额外信息的结构的指针。未使用的位将用于缓存简单信息。比如类型是否为 POD,移动/复制可构造/可赋值等。 -
具有用于57 位规范地址的 5 级页表的 CPU 可能很快就会出现。 Intel 已经发布了software.intel.com/sites/default/files/managed/2b/80/… / en.wikipedia.org/wiki/Intel_5-level_paging 并且已经在 Linux 内核中支持它,因此它已经为实际硬件的出现做好了准备。 (我不知道它是否会出现在冰湖中。)另见Why in 64bit the virtual address are 4 bits short (48bit long) compared with the physical address (52 bit long)?
标签: c++11 pointers x86-64 canonical-form