簡體   English   中英

檢查兩個指針​​是否在同一頁面上

[英]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;
    }

ab是指針,所以它們之間的距離是:

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;
    }

你的代碼有很多問題。

  1. 您正在比較函數參數的地址(它們並排,在堆棧上),而不是指針
  2. 你無端和8000比較difference
  3. 4K != 4000
  4. 想象一個地址是3K,另一個是5K,根據你的代碼,它們在同一頁面上。
  5. 返回值的錯誤選擇

名稱AreOnSamePage()暗示該函數返回01 我覺得讓它返回-14或其他值很奇怪。

如果一個頁面是 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保證足夠寬以存儲指針值。

你試圖解決面試問題是錯誤的。

您應該比較ab 不是&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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM