简体   繁体   English

64位减法结果为32位整数

[英]64-bit subtraction result to 32-bit integer

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. 但是这段代码在64位下产生了编译错误,因为void *不再是32位,所以我将代码修改为以下内容。

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? 在当前的64位Linux体系结构下,此函数返回错误结果的可能性有多大? ie, what is the likelihood of two virtual addresses being apart for more than 0x7FFFFFFF? 也就是说,两个虚拟地址分开超过0x7FFFFFFF的可能性是多少?

我想你想要的

int compare(void* A, void* B) { return (A > B) - (A < B); }

On my linux machine, here's an example. 在我的linux机器上,这是一个例子。

I have a copy of tcsh running. 我有一个tcsh运行的副本。 It has a process id of 9732. We can look at the memory maps of it by examining /proc/<pid>/maps . 它的进程ID为9732.我们可以通过检查/proc/<pid>/maps来查看它的内存/proc/<pid>/maps

From the table below, we can see that heap data is stored around 0x01e30000 , while stack data is stored around 0x7fffca3e6000 . 从下表中,我们可以看到堆数据存储在0x01e30000左右,而堆栈数据存储在0x7fffca3e6000左右。 So in a simple case, if you compare a malloc allocated pointer with a stack pointer, you'll see a significant difference in pointers. 所以在一个简单的例子中,如果你将malloc分配的指针与堆栈指针进行比较,你会看到指针的显着差异。

[1:02pm][wlynch@charcoal Harrow] cat /proc/9732/maps
00400000-0045a000 r-xp 00000000 09:00 44826689                           /bin/tcsh
0065a000-0065e000 rw-p 0005a000 09:00 44826689                           /bin/tcsh
0065e000-00674000 rw-p 00000000 00:00 0 
0085d000-0085f000 rw-p 0005d000 09:00 44826689                           /bin/tcsh
01e30000-01f78000 rw-p 00000000 00:00 0                                  [heap]
38a3c00000-38a3c1e000 r-xp 00000000 09:00 16253177                       /lib64/ld-2.12.so
38a3e1e000-38a3e1f000 r--p 0001e000 09:00 16253177                       /lib64/ld-2.12.so
38a3e1f000-38a3e20000 rw-p 0001f000 09:00 16253177                       /lib64/ld-2.12.so
38a3e20000-38a3e21000 rw-p 00000000 00:00 0 
38a4400000-38a4575000 r-xp 00000000 09:00 16253179                       /lib64/libc-2.12.so
38a4575000-38a4775000 ---p 00175000 09:00 16253179                       /lib64/libc-2.12.so
38a4775000-38a4779000 r--p 00175000 09:00 16253179                       /lib64/libc-2.12.so
38a4779000-38a477a000 rw-p 00179000 09:00 16253179                       /lib64/libc-2.12.so
38a477a000-38a477f000 rw-p 00000000 00:00 0 
38a4800000-38a4802000 r-xp 00000000 09:00 16253186                       /lib64/libdl-2.12.so
38a4802000-38a4a02000 ---p 00002000 09:00 16253186                       /lib64/libdl-2.12.so
38a4a02000-38a4a03000 r--p 00002000 09:00 16253186                       /lib64/libdl-2.12.so
38a4a03000-38a4a04000 rw-p 00003000 09:00 16253186                       /lib64/libdl-2.12.so
38af000000-38af01d000 r-xp 00000000 09:00 16253156                       /lib64/libtinfo.so.5.7
38af01d000-38af21d000 ---p 0001d000 09:00 16253156                       /lib64/libtinfo.so.5.7
38af21d000-38af221000 rw-p 0001d000 09:00 16253156                       /lib64/libtinfo.so.5.7
38b0c00000-38b0c58000 r-xp 00000000 09:00 16253191                       /lib64/libfreebl3.so
38b0c58000-38b0e57000 ---p 00058000 09:00 16253191                       /lib64/libfreebl3.so
38b0e57000-38b0e59000 rw-p 00057000 09:00 16253191                       /lib64/libfreebl3.so
38b0e59000-38b0e5d000 rw-p 00000000 00:00 0 
38b1000000-38b1007000 r-xp 00000000 09:00 16253192                       /lib64/libcrypt-2.12.so
38b1007000-38b1207000 ---p 00007000 09:00 16253192                       /lib64/libcrypt-2.12.so
38b1207000-38b1208000 r--p 00007000 09:00 16253192                       /lib64/libcrypt-2.12.so
38b1208000-38b1209000 rw-p 00008000 09:00 16253192                       /lib64/libcrypt-2.12.so
38b1209000-38b1237000 rw-p 00000000 00:00 0 
7f03aa9a0000-7f03aa9ac000 r-xp 00000000 09:00 16252957                   /lib64/libnss_files-2.12.so
7f03aa9ac000-7f03aabab000 ---p 0000c000 09:00 16252957                   /lib64/libnss_files-2.12.so
7f03aabab000-7f03aabac000 r--p 0000b000 09:00 16252957                   /lib64/libnss_files-2.12.so
7f03aabac000-7f03aabad000 rw-p 0000c000 09:00 16252957                   /lib64/libnss_files-2.12.so
7f03aabbc000-7f03aabc3000 r--s 00000000 09:00 5769665                    /usr/lib64/gconv/gconv-modules.cache
7f03aabc3000-7f03b0a54000 r--p 00000000 09:00 5506757                    /usr/lib/locale/locale-archive
7f03b0a54000-7f03b0a58000 rw-p 00000000 00:00 0 
7f03b0a5b000-7f03b0a67000 r--p 00000000 09:00 5510943                    /usr/share/locale/en/LC_MESSAGES/tcsh
7f03b0a67000-7f03b0a68000 rw-p 00000000 00:00 0 
7fffca3e6000-7fffca3fb000 rw-p 00000000 00:00 0                          [stack]
7fffca3ff000-7fffca400000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

This looks like a sort comparison function, so all that matters is the sign of the result. 这看起来像一个排序比较函数,所以最重要的是结果的符号。

int compare(void *A, void* B)
{
  if (A < B) return -1;
  if (A > B) return 1;
  return 0;
 }

You shouldn't be returning an int, but rather a uintptr_t. 你不应该返回一个int,而是一个uintptr_t。 Make sure variables set to this function are uintptr_t too. 确保设置为此函数的变量也是uintptr_t。

uintptr_t compare(void* A, void* B) { return (uintptr_t)A - (uintptr_t)B; }

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. 机会可能非常小,但这并不意味着它是一个例外情况。

int compare (void*p, void*q) { return (p==q)?0:((char*)p < (char*)q)?-1:1; }

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 , return ptrdiff_t which as its name implies is an integral type big enough to hold pointer differences. 返回ptrdiff_t而不是返回int ,顾名思义,它是一个足以保持指针差异的整数类型。 You do still have to cast, although I chose char* instead of int because it lets you use static_cast : 你仍然需要static_cast转换,虽然我选择了char*而不是int因为它允许你使用static_cast

ptrdiff_t compare(void* A, void* B) { return static_cast<char*>(A) - static_cast<char*>(B); }

Finally if you're using this with C's qsort , just take the simple way: Use std::sort which can use a single < and doesn't need to do any subtraction at all! 最后,如果您使用C的qsort ,只需采用简单的方法:使用std::sort ,它可以使用单个<并且根本不需要做任何减法!

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. 在x86和AMD64上,使用<>指针之间的比较很可能在实践中起作用。 But difference based methods can fail due to int-overflows. 但是由于int溢出,基于差异的方法可能会失败。

There is an existing function named "Compare," which is 有一个名为“比较”的现有功能,即

 int compare(void* A, void* B) { return (int)A - (int)B; } 

This is already broken on 32 bit systems where pointers the high bit set exist. 这已经在32位系统上被破坏,其中存在高位集的指针。 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). 在Windows上,这可能发生在使用/LARGEADDRESSAWARE (允许3GB用户模式地址空间)的应用程序中。 I don't know enough about Linux to know if it can happen there. 我不太了解Linux,知道它是否会在那里发生。

So you should use Ben Voigt's code even on 32 bit systems. 因此,即使在32位系统上也应该使用Ben Voigt的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM