2010-06-11 32 views
1

下面這個函數用來獲取這是此頁內的地址的頁面的基地址:什麼是pAddress&〜訣竅(PAGE_SIZE - 1)獲得頁面的基地址

void* GetPageAddress(void* pAddress) 
{ 
    return (void*)((ULONG_PTR)pAddress & ~(PAGE_SIZE - 1)); 
} 

但我無法完全理解它,它在這裏扮演的訣竅是什麼?

結論:
就個人而言,我認爲Amardeep的解釋加上Alex B的例子是最好的答案。由於亞歷克斯B的答案已被投票,我想接受阿馬迪普的答案作爲官方的答案來突出它!謝謝大家。

回答

6

它所做的是清除適合由頁面大小創建的掩碼內的地址位。實際上,它獲得一個塊的第一個有效地址。

PAGE_SIZE必須是2的冪,並且用在地址中設置的單個位來表示。

該掩碼是通過從PAGE_SIZE中減去一個來創建的。這有效地設置了比頁面大小位低的所有位。 〜然後將所有這些位補全爲零,並設置比掩碼更高階的所有位。 &然後有效地去除所有較低位,留下包含原始地址的頁面的實際基地址。

+0

」然後,將所有這些位補全爲零,並設置比掩碼更高位的所有位。「----要匹配&左邊句柄操作數的大小,右邊? – 2010-06-11 15:28:15

+0

〜將返回與其操作數相同的大小。在這種情況下,如果PAGE_SIZE只是一個定義爲文字數字的宏,它將默認爲目標平臺上的任何「int」,可能是32位。您提供的代碼示例在64位系統上無效。它需要:return(void *)((ULONG_PTR)pAddress&〜(void *)(PAGE_SIZE - 1)); – 2010-06-11 17:34:44

4

當PAGE_SIZE是某個2的冪(例如4096)時,這會清除指定頁面的所有位。

+0

是的,似乎PAGE_SIZE必須是2的冪,否則結果是錯誤的,但是爲什麼〜(PAGE_SIZE-1),我想我們可以使用PAGE_SIZE – 2010-06-11 15:11:55

+2

@Dbger:PAGE_SIZE,如果表示2的冪通過一點點。爲了創建正確大小的掩碼,您需要設置比這個位低的所有位。 – 2010-06-11 15:14:32

+0

如果PAGE_SIZE是2的冪,那麼補充它會給你一個只有一個零位的掩碼,這沒有多大幫助。 – TMN 2010-06-11 15:20:40

14

該函數清除給定地址的低位,從而生成其頁面的地址。

例如,如果PAGE_SIZE爲4096,則在32位二進制:

PAGE_SIZE  = 00000000000000000001000000000000b 
    PAGE_SIZE - 1 = 00000000000000000000111111111111b 
~(PAGE_SIZE - 1) = 11111111111111111111000000000000b 

如果按位,並將其與一個32位的地址,它會變成較低位成零,舍入地址到最近的4096個字節的頁面地址。

~(PAGE_SIZE - 1)    = 11111111111111111111000000000000b 
        pAddress = 11010010100101110110110100100100b 
~(PAGE_SIZE - 1) & pAddress = 11010010100101110110000000000000b 

所以,十進制,原始地址是3533139236,頁地址(與低位地址剝離)是3533135872 = 862582 x 4096,是4096的倍數。

+1

與數字示例很好的工作。 – mskfisher 2010-06-11 15:38:19

1

這只是一個清除低位位的棘手方法。

另一種方式來實現它可能是

void* GetPageAddress(void* pAddress) 
{ 
    return pAddress - pAddress%PAGE_SIZE; 
} 

這可能將無法編譯,因爲你需要轉換類型了一下,咬它顯示的算法。

實際上它正在獲得小於pAddress的PAGE_SIZE的最大倍數。 「

相關問題