以下函数用于获取该页面内地址的页面基地址:
void* GetPageAddress(void* pAddress)
{
return (void*)((ULONG_PTR)pAddress & ~(PAGE_SIZE - 1));
}
但我无法理解,它在这里扮演的诀窍是什么?
结论:
就个人而言,我认为Amardeep的解释加上Alex B的例子是最好的答案。由于亚历克斯B的答案已经被投票,我想接受Amardeep的答案作为正式的答案来突出它!谢谢大家。
答案 0 :(得分: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 :(得分:6)
它的作用是清除适合页面大小创建的掩码的地址位。实际上它获得了一个块的第一个有效地址。
PAGE_SIZE必须是2的幂,并由地址中设置的单个位表示。
通过从PAGE_SIZE中减去一个来创建掩码。这有效地设置了比页面大小位低的所有位。然后,〜将所有这些位补充为零,并设置比掩码更高阶的所有位。 &然后有效地剥离所有低位,留下包含原始地址的页面的实际基址。
答案 2 :(得分:4)
当PAGE_SIZE为2的幂(例如4096)时,会清除指定页面下方的所有位。
答案 3 :(得分:1)
这只是清除低位的一种棘手方法。
实现它的另一种方法可能是
void* GetPageAddress(void* pAddress)
{
return pAddress - pAddress%PAGE_SIZE;
}
这可能无法编译,因为您需要稍微转换类型,它会显示算法。
实际上,它获得的PAGE_SIZE的最大倍数小于pAddress。