簡體   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