将指针类型转换为 uint64_t 时,通过 uintptr_t 会带来任何安全性吗?
Does going through uintptr_t bring any safety when casting a pointer type to uint64_t?
请注意,从语言律师的角度来看,这纯粹是一个学术问题。这是关于完成转换的理论上最安全的方法。
假设我有一个 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 说(强调我的):
Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions (except when converting between integers and pointers or on obscure architectures where pointer representation depends on its type).
因此,理论上,指针表示没有被定义为任何特定的东西;从指针到 uintptr_t
理论上可能会执行某种转换 以使指针可表示为整数。之后,我强行提取了低64位。而直接转换为 uint64_t
不会触发上述转换,因此我会得到不同的结果。
我的解释是否正确,或者这两个演员在理论上也没有任何区别吗?
FWIW,在 32 位系统上,显然向无符号 64 位的扩展转换可以进行符号扩展,如 this case 中所示。但是在 64 位上我不应该有这个问题。
您对那个(令人震惊的非正式,对于 cppreference)段落的分析太仔细了。它试图解决的问题只是其他类型转换可能涉及转换操作(float/int 东西、符号扩展、指针调整),而 reinterpret_cast 具有直接重用位的风格。
如果将指针重新解释为整数并且整数类型不够大,则会出现编译时错误。如果它足够大,你很好。 uintptr_t
除了保证(如果存在)它足够大之外没有什么神奇的,如果你随后重新转换为更小的类型,你无论如何都会失去它。要么 64 位就足够了,在这种情况下,你可以得到与任何一种类型相同的保证,否则,无论你做什么,你都会被搞砸。如果您的实施愿意在 reinterpret_cast 内做一些 奇怪的 ,这可能会产生与(比如)bit_cast 不同的结果,这两种方法都不能保证也不能阻止这种情况。
当然,这并不是说两者一定相同。考虑具有 32 位指针的 DS9k-ish 架构,其中指向 uint64_t 的指针的 reinterpret_cast 导致指针位在低字和高字中重复。如果你直接进入 uint64_t,你会得到两个副本,如果你通过 32 位 uintptr_t,你会在上半部分得到零。那样的话,哪一个是“对的”就见个人意见了。
请注意,从语言律师的角度来看,这纯粹是一个学术问题。这是关于完成转换的理论上最安全的方法。
假设我有一个 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 说(强调我的):
Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions (except when converting between integers and pointers or on obscure architectures where pointer representation depends on its type).
因此,理论上,指针表示没有被定义为任何特定的东西;从指针到 uintptr_t
理论上可能会执行某种转换 以使指针可表示为整数。之后,我强行提取了低64位。而直接转换为 uint64_t
不会触发上述转换,因此我会得到不同的结果。
我的解释是否正确,或者这两个演员在理论上也没有任何区别吗?
FWIW,在 32 位系统上,显然向无符号 64 位的扩展转换可以进行符号扩展,如 this case 中所示。但是在 64 位上我不应该有这个问题。
您对那个(令人震惊的非正式,对于 cppreference)段落的分析太仔细了。它试图解决的问题只是其他类型转换可能涉及转换操作(float/int 东西、符号扩展、指针调整),而 reinterpret_cast 具有直接重用位的风格。
如果将指针重新解释为整数并且整数类型不够大,则会出现编译时错误。如果它足够大,你很好。 uintptr_t
除了保证(如果存在)它足够大之外没有什么神奇的,如果你随后重新转换为更小的类型,你无论如何都会失去它。要么 64 位就足够了,在这种情况下,你可以得到与任何一种类型相同的保证,否则,无论你做什么,你都会被搞砸。如果您的实施愿意在 reinterpret_cast 内做一些 奇怪的 ,这可能会产生与(比如)bit_cast 不同的结果,这两种方法都不能保证也不能阻止这种情况。
当然,这并不是说两者一定相同。考虑具有 32 位指针的 DS9k-ish 架构,其中指向 uint64_t 的指针的 reinterpret_cast 导致指针位在低字和高字中重复。如果你直接进入 uint64_t,你会得到两个副本,如果你通过 32 位 uintptr_t,你会在上半部分得到零。那样的话,哪一个是“对的”就见个人意见了。