繁体   English   中英

64位减法结果为32位整数

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

有一个名为“比较”的现有功能,即

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的可能性是多少?

我想你想要的

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

在我的linux机器上,这是一个例子。

我有一个tcsh运行的副本。 它的进程ID为9732.我们可以通过检查/proc/<pid>/maps来查看它的内存/proc/<pid>/maps

从下表中,我们可以看到堆数据存储在0x01e30000左右,而堆栈数据存储在0x7fffca3e6000左右。 所以在一个简单的例子中,如果你将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]

这看起来像一个排序比较函数,所以最重要的是结果的符号。

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

你不应该返回一个int,而是一个uintptr_t。 确保设置为此函数的变量也是uintptr_t。

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

如果由于某种原因无法执行此操作,则应检查值是否在范围内,否则抛出错误。 机会可能非常小,但这并不意味着它是一个例外情况。

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

如果您碰巧比较堆栈和堆上的地址,我会说差异很可能大于那个(因为通常堆从底部长大,堆栈从顶部向下增长)。

返回ptrdiff_t而不是返回int ,顾名思义,它是一个足以保持指针差异的整数类型。 你仍然需要static_cast转换,虽然我选择了char*而不是int因为它允许你使用static_cast

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

最后,如果您使用C的qsort ,只需采用简单的方法:使用std::sort ,它可以使用单个<并且根本不需要做任何减法!

首先:只有指针指向同一个数组时,才会定义指针比较。 但我认为只要它在实践中起作用你就不在乎。

在x86和AMD64上,使用<>指针之间的比较很可能在实践中起作用。 但是由于int溢出,基于差异的方法可能会失败。

有一个名为“比较”的现有功能,即

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

这已经在32位系统上被破坏,其中存在高位集的指针。 这不仅会导致奇怪的排序,而且会违反订单所需的传递属性。 在Windows上,这可能发生在使用/LARGEADDRESSAWARE (允许3GB用户模式地址空间)的应用程序中。 我不太了解Linux,知道它是否会在那里发生。

因此,即使在32位系统上也应该使用Ben Voigt的代码。

暂无
暂无

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

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