pAddress& amp;中的技巧是什么? 〜(PAGE_SIZE - 1)获取页面的基地址

时间:2010-06-11 15:06:21

标签: c++ c bit-manipulation

以下函数用于获取该页面内地址的页面基地址:

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

但我无法理解,它在这里扮演的诀窍是什么?

结论:
就个人而言,我认为Amardeep的解释加上Alex B的例子是最好的答案。由于亚历克斯B的答案已经被投票,我想接受Amardeep的答案作为正式的答案来突出它!谢谢大家。

4 个答案:

答案 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。