64位减法结果为32位整数
64-bit subtraction result to 32-bit integer
有一个名为"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的代码。
- 如何忽略32位整数中的特定位
- 检测 32 位整数溢出
- 将 64 位整数中的每个其他位与 32 位整数进行比较
- 对 32 位整数进行哈希处理比对 3 个 16 位整数的哈希进行按位运算慢?
- SSE 整数 2^n 的 2 次方,对于没有 AVX2 的 32 位整数
- 32 位整数缩放,无溢出
- Visual C 32位整数从文件到8位字符到文件 - 程序在某些整数上崩溃
- 将 32 位浮点数和不强制转换的 32 位整数与双精度进行比较,当其中一个值可能太大而无法完全适合另一种类型时
- 尝试从另一个过程读取32位整数时,ReadProcessMemory崩溃了
- 使用非 32 位整数是否合理
- 这种计算 32 位整数中设置位数的算法如何工作
- 是否可以在 64 位应用程序中使用 32 位整数
- 在32位整数中编码4个值
- 使用 Python 编程的 32 位整数中有多少个'1'
- 从 BYTE 数组读取 32 位整数.VC++
- 在64位计算机中分配32位整数数组
- 将2^31赋给有符号和无符号的32位整数变量后的奇怪结果
- 如何将32位整数转换为32位浮点数,以保持顺序
- c++中8位整数和32位整数之间的与运算
- 64位和32位整数