【发布时间】:2022-01-04 02:00:10
【问题描述】:
请注意,从语言律师的角度来看,这纯粹是一个学术问题。这是关于完成转换的理论上最安全的方法。
假设我有一个void*,我需要将它转换为一个 64 位整数。原因是该指针保存了错误指令的地址。我希望将此报告给我的后端以进行记录,并且我使用固定大小的协议 - 所以我正好有 64 位可用于地址。
演员阵容当然是由实现定义的。我知道我的平台(64 位 Windows)允许这种转换,所以实际上只需 reinterpret_cast<uint64_t>(address) 就可以了。
但我想知道:从理论上讲,首先转换为uintptr_t 是否更安全?即:static_cast<uint64_t>(reinterpret_cast<uintptr_t>(address))。 https://en.cppreference.com/w/cpp/language/reinterpret_cast 说(强调我的):
与 static_cast 不同,但与 const_cast 类似,reinterpret_cast 表达式不会编译为任何 CPU 指令(在整数和指针之间转换或在指针表示取决于其类型的晦涩架构中除外)。 p>
所以,理论上,指针表示并没有被定义为特别的东西;从指针指向uintptr_t理论上可能会执行某种转换,以使指针可表示为整数。之后,我强行提取低 64 位。而直接转换为uint64_t 不会触发上述转换,因此我会得到不同的结果。
我的解释是否正确,或者这两种类型在理论上也没有任何区别?
FWIW,在 32 位系统上,显然扩大到无符号 64 位的转换可以符号扩展,如 this case。但是在 64 位上我不应该有这个问题。
【问题讨论】:
-
DS9K 上的
void*具有 8 位堆标记、56 位段标记、64 位低访问、64 位高访问和 64 位偏移。那些 256 位在 64 位整数中不太适合。它们确实适合 256 位uintptr_t。 YMMV 基于您正在考虑的平台。 -
"原因是该指针保存了错误指令的地址;" --> 至少在 C 语言中(我认为适用于 C++),
void*对于 对象。指向函数(或函数中的地址)的指针可能需要比void *更宽的内容。所以开始的前提是错误的——甚至在尝试转换为整数之前。我怀疑是否有任何规范支持指令地址。代码在规范之外的实现定义区域中。最好“将其报告给我的后端以进行记录”将其报告为指针,而不是整数。 -
@chux-ReinstateMonica 有条件地支持 C++ 中的函数指针,并且唯一保证(如果支持)转换为
void*并返回会产生相同的函数指针值。但我认为,一旦您拥有void*,就应该应用将void*转换为整数的规则。 eel.is/c++draft/expr.reinterpret.cast#8 当然一般的指令地址是没有定义的。 -
@user17732522 谢谢。如果可能的话,似乎问题应该是直接将函数指针(或指令地址)转换为某个宽整数,而不是通过
void *。 “指针可以显式转换为任何大到足以容纳其类型的所有值的整数类型。映射函数是实现定义的。” -
@chux-ReinstateMonica 在这种情况下,操作系统将指令地址作为
void*:docs.microsoft.com/en-us/windows/win32/api/winnt/… 提供给您。当然,这是我们进入特定实施领域的地方。
标签: c++ language-lawyer