64 位减法结果转为 32 位整数
有一个名为“Compare”的现有函数,
int compare(void* A, void* B) { return (int)A - (int)B; }
我知道这是一种残暴的做法,但我没有编写那段代码,它已经在很多地方使用了。但此代码在 64 位下生成编译错误,因为 void* 不再是 32 位,因此我将代码修复为以下内容。
int compare(void* A, void* B) { return (long long)A - (long long)B; }
在当前 64 位 Linux 架构下,该函数返回错误结果的可能性有多大?即,两个虚拟地址相距超过 0x7FFFFFFF 的可能性有多大?
There is an existing function named "Compare," which is
int compare(void* A, void* B) { return (int)A - (int)B; }
I am aware that this is an atrocious practice, but I did not write that piece of code and it is being used in many places already. But this code was generating a compilation error under 64-bit, since void* is no longer 32-bit, so I fixed the code to the following.
int compare(void* A, void* B) { return (long long)A - (long long)B; }
What is the likelihood of this function returning an incorrect result under current 64-bit Linux architecture? i.e, what is the likelihood of two virtual addresses being apart for more than 0x7FFFFFFF?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我想你想要
I think you want
在我的 Linux 机器上,这是一个示例。
我有一份 tcsh 正在运行。它的进程 ID 为 9732。我们可以通过检查
/proc//maps
来查看它的内存映射。从下表中我们可以看到,堆数据存储在
0x01e30000
左右,而栈数据存储在0x7fffca3e6000
左右。因此,在简单的情况下,如果将 malloc 分配的指针与堆栈指针进行比较,您会发现指针存在显着差异。On my linux machine, here's an example.
I have a copy of tcsh running. It has a process id of 9732. We can look at the memory maps of it by examining
/proc/<pid>/maps
.From the table below, we can see that heap data is stored around
0x01e30000
, while stack data is stored around0x7fffca3e6000
. So in a simple case, if you compare a malloc allocated pointer with a stack pointer, you'll see a significant difference in pointers.这看起来像一个排序比较函数,所以重要的是结果的符号。
This looks like a sort comparison function, so all that matters is the sign of the result.
您不应该返回 int,而应该返回 uintptr_t。确保为此函数设置的变量也是 uintptr_t。
如果您出于某种原因无法执行此操作,那么您应该检查这些值是否在范围内,如果不在范围内,则抛出错误。可能性很小,但这并不意味着这是一个例外。
You shouldn't be returning an int, but rather a uintptr_t. Make sure variables set to this function are uintptr_t too.
If you can't do this for whatever reason, then you should be checking that the values are within range and throw an error if not. The chance is probably very small, but that doesn't mean it's an exceptional case.
如果您碰巧比较堆栈和堆上的地址,我会说差异很可能比这更大(因为通常堆从底部向上增长,而堆栈从顶部向下增长)。
返回 ptrdiff_t ,而不是返回 int ,顾名思义,它是一个足够大的整数类型,可以容纳指针差异。尽管我选择了
char*
而不是int
因为它允许您使用static_cast
,但您仍然需要强制转换:最后,如果您使用此使用C的
qsort
,只需采取简单的方法:使用std::sort
,它可以使用单个<
并且不需要这样做任何减法都可以!If you happen to compare addresses on the stack and heap I would say it's quite possible that the difference could be larger than that (since typically the heap grows up from the bottom and the stack grows down from the top).
Instead of returning
int
, returnptrdiff_t
which as its name implies is an integral type big enough to hold pointer differences. You do still have to cast, although I chosechar*
instead ofint
because it lets you usestatic_cast
:Finally if you're using this with C's
qsort
, just take the simple way: Usestd::sort
which can use a single<
and doesn't need to do any subtraction at all!首先:仅当指针指向同一数组时才定义指针比较。但我认为只要它在实践中有效,你就不会关心。
在 x86 和 AMD64 上,
<
和>
指针之间的比较在实践中很可能有效。但基于差异的方法可能会由于整数溢出而失败。在存在高位集指针的 32 位系统上已被破坏。这不仅会导致奇怪的排序,而且违反了顺序所需的传递性属性。在 Windows 上,使用
/LARGEADDRESSAWARE
(允许 3GB 用户模式地址空间)的应用程序可能会发生这种情况。我对 Linux 的了解还不够,不知道它是否会发生在那里。因此,即使在 32 位系统上,您也应该使用 Ben Voigt 的代码。
First of all: Pointer comparisons are only defined if the pointers point into the same array. But I assume you don't care as long as it works in practice.
On x86 and AMD64 comparisons between pointers with
<
and>
will most likely work in practice. But difference based methods can fail due to int-overflows.This is already broken on 32 bit systems where pointers the high bit set exist. This will not only lead to a strange ordering, but violates the transitivity property an order needs. On windows this can happen with applications that use
/LARGEADDRESSAWARE
(which allows 3GB of user mode address space). I don't know enough about Linux to know if it can happen there.So you should use Ben Voigt's code even on 32 bit systems.