[英]Checking if two pointers are on the same page
我看到了這個面試問題,想知道我的功能是否在做它應該做的,或者是否有更好的方法來做到這一點。
這是問題的確切引用:
操作系統通常按頁分配內存,使得頁的基地址為 0、4K、8K 等。給定兩個地址(指針),編寫一個函數來查找兩個指針是否在同一頁上。 這是函數原型: int AreOnSamePage (void * a, void * b);
這是我的實現。 如果它在 4k 和 8k 之間,我讓它返回 4。 如果它在 0 到 4k 之間,它返回 1,如果它超過 8k,它返回 -1。 我得到了正確的地址嗎? 面試問題措辭含糊。 由於地址可能非常大,因此使用 long 是否正確?
int AreOnSamePage(void* a, void* b){
long difference = abs(&a - &b);
printf("%ld %ld\n",(long)&a,(long)&b);
if(difference > 8000)
return -1;
if(difference >= 4000)
return 4;
return 1;
}
a
和b
是指針,所以它們之間的距離是:
ptrdiff_t difference = (ptrdiff_t) abs((char *)a - (char *) b)
但你不需要它。 兩個指針在同一頁上,如果
(uintptr_t)a / 4096 == ( uintptr_t ) b / 4096
否則它們在不同的頁面上。 所以:
int AreOnSamePage(void* a, void* b) {
const size_t page_size = 4096;
if ( (uintptr_t) a / page_size == (uintptr_t) b / page_size)
return 1;
else
return 0;
}
你的代碼有很多問題。
difference
名稱AreOnSamePage()
暗示該函數返回0
或1
; 我覺得讓它返回-1
、 4
或其他值很奇怪。
如果一個頁面是 4KB,那么這意味着你需要 12 位來索引頁面內的每個字節(因為 2^12 = 4096),所以只要兩個指針值的N-12
最高有效位比較相等,那么你知道它們在同一頁上(其中N
是指針的大小)。
所以你可以這樣做:
#include <stdint.h>
static const uintptr_t PAGE_SIZE = 4096;
static const uintptr_t PAGE_MASK = ~(PAGE_SIZE-1);
int AreOnSamePage(void *a, void *b) {
return (((uintptr_t) a) & PAGE_MASK) == (((uintptr_t) b) & PAGE_MASK);
}
PAGE_MASK
是一個位掩碼,擁有所有N-12
設置為1,最顯著位和12個最低顯著位設置為0,這樣做的按位AND
一個地址,我們有效地清除至少顯著12位(偏移到頁面),所以我們只能比較其他重要的位。
請注意,與long
不同, uintptr_t
保證足夠寬以存儲指針值。
你試圖解決面試問題是錯誤的。
您應該比較a
和b
。 不是&a
和&b
。
但即便如此,它仍然是錯誤的。 考慮指針a
指向第0頁的最后位置,指針b
指向第1頁的第一個位置。第1頁是第0頁之后的那個。
它們的區別是 1。但是它們在不同的頁面中。
為了正確實現它,您應該考慮一個頁面是 4Kib 長。 4Kib = 2^12 = 4096。因此,如果一對指針在同一頁中,則保存最后 12 個指針的所有位將相等。
#include<stdint.h>
int AreOnSamePage(void* a, void* b){
return ((intptr_t)a & ~(intptr_t)0xFFF) ==
((intptr_t)b & ~(intptr_t)0xFFF);
}
一個更簡潔但等效的實現:
int AreOnSamePage(void* a, void* b){
return ((intptr_t)a)>>12 == ((intptr_t)b)>>12;
}
如前所述,您應該使用uintptr_t
來處理指針。 但是,當您測試距離而不是頁面時,您的代碼是錯誤的。 此外,您會忘記計算機使用 2 的冪。 8000
沒有; 那將是8192
。 4000
類似。
最快的測試方法是:
#include <stdbool.h>
#include <stdint.h>
// this should better be found in a system header:
#define PAGESIZE 4096U
bool samePage(void *a, void *b)
{
return ((uintptr_t)a ^ (uintptr_t)b) < PAGESIZE;
}
或者:
return !(((uintptr_t)a ^ (uintptr_t)b) / PAGESIZE);
請注意,除法的結果將轉換為bool
。 如果這被用作內聯,它將只測試零/非零。
XOR 會將所有相等的位歸零。 因此,如果任何高階位不同,它們將在 XOR 之后設置,並使結果 >= PAGESIZE。 這可以為您節省一個分區或屏蔽。
當然,這要求 PAGESIZE 是 2 的冪。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.