64 位减法结果转为 32 位整数

发布于 2024-12-12 19:19:02 字数 379 浏览 0 评论 0原文

有一个名为“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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

桜花祭 2024-12-19 19:19:03

我想你想要

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

I think you want

int compare(void* A, void* B) { return (A > B) - (A < B); }
喵星人汪星人 2024-12-19 19:19:03

在我的 Linux 机器上,这是一个示例。

我有一份 tcsh 正在运行。它的进程 ID 为 9732。我们可以通过检查 /proc//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]

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 around 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.

[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]
殊姿 2024-12-19 19:19:03

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

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

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;
 }
病女 2024-12-19 19:19:03

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

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

如果您出于某种原因无法执行此操作,那么您应该检查这些值是否在范围内,如果不在范围内,则抛出错误。可能性很小,但这并不意味着这是一个例外。

You shouldn't be returning an int, but rather a uintptr_t. Make sure variables set to this function are uintptr_t too.

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.

离去的眼神 2024-12-19 19:19:03

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

返回 ptrdiff_t ,而不是返回 int ,顾名思义,它是一个足够大的整数类型,可以容纳指针差异。尽管我选择了 char* 而不是 int 因为它允许您使用 static_cast,但您仍然需要强制转换:

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

最后,如果您使用此使用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, return ptrdiff_t which as its name implies is an integral type big enough to hold pointer differences. You do still have to cast, although I chose char* instead of int because it lets you use 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!

仲春光 2024-12-19 19:19:03
int compare (void*p, void*q) { return (p==q)?0:((char*)p < (char*)q)?-1:1; }
int compare (void*p, void*q) { return (p==q)?0:((char*)p < (char*)q)?-1:1; }
倾其所爱 2024-12-19 19:19:03

首先:仅当指针指向同一数组时才定义指针比较。但我认为只要它在实践中有效,你就不会关心。

在 x86 和 AMD64 上,<> 指针之间的比较在实践中很可能有效。但基于差异的方法可能会由于整数溢出而失败。

有一个名为“Compare”的现有函数,它是

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

在存在高位集指针的 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.

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. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文