64位减法结果为32位整数

64-bit subtraction result to 32-bit integer

本文关键字:32位 整数 结果 64位      更新时间:2023-10-16

有一个名为"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的可能性是多少?

我想你要

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

在我的linux机器上,下面是一个示例:

我有一个tcsh的拷贝正在运行。进程id为9732。我们可以通过检查/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,而是返回ptrdiff_t,顾名思义,它是一个足够大的整数类型,可以保存指针的差异。您仍然需要强制转换,尽管我选择了char*而不是int,因为它允许您使用static_cast:

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

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

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

首先:指针比较只有在指针指向同一个数组时才定义。但我想你不会在意,只要它在实践中有效。

在x86和AMD64上,指针与<>之间的比较很可能在实践中工作。但是基于差异的方法可能会因为int-overflow而失败。

存在一个名为"Compare,"这是

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

这在32位系统中已经被打破了,因为指针的高位集存在。这不仅会导致奇怪的排序,还会违反顺序所需的传递性。在windows上,使用/LARGEADDRESSAWARE(允许3GB的用户模式地址空间)的应用程序可能会发生这种情况。我不太了解Linux,不知道它是否会发生。

所以即使在32位系统上也应该使用Ben Voigt的代码。