线性地址目录位与页位提取的位掩码使用问题
问题成因
((1 << x) -1) << y生成的是对齐到原始比特位置的掩码,和目标地址做按位与操作,仅能实现「清零所有非目标区间比特位」的效果,不会改变目标比特位所在的位置。
提取偏移量时能得到正确结果,是因为偏移量的起始位y=0,按位与后目标位段天然处于最低位,不需要额外移位就能得到纯数值。提取目录、页这类高位段时,按位与得到的结果保留了目标位段的原始位置,低位全补0,本质是「目标位段数值左移y位」的结果,自然不是预期的纯位段值。
另外原代码的目录位段掩码参数也有误:32位地址的22~31位共10个连续比特,x应该取10,不是9。
正确实现方式
提取连续比特位段需要两个步骤:
- 用对齐掩码和地址做按位与,清零所有非目标位
- 将按位与的结果右移y位,把目标位段平移到最低位,得到纯数值
三个位段的正确实现代码如下:
#include <stdint.h> #include <stdio.h> // 偏移量:0~11位,共12位,起始位y=0 #define GET_OFFSET(addr) (((addr) & (((1u << 12) - 1) << 0)) >> 0) // 页位段:12~21位,共10位,起始位y=12 #define GET_PAGE(addr) (((addr) & (((1u << 10) - 1) << 12)) >> 12) // 目录位段:22~31位,共10位,起始位y=22 #define GET_DIR(addr) (((addr) & (((1u << 10) - 1) << 22)) >> 22) int main(void) { uint32_t addr = 0x12345678; printf("dir: %#x, page: %#x, offset: %#x", GET_DIR(addr), GET_PAGE(addr), GET_OFFSET(addr)); // 输出:dir: 0x48, page: 0x345, offset: 0x678 return 0; }
注意事项
所有移位操作必须使用无符号整数类型,避免有符号数算术右移时补符号位,导致结果错误。
内容的提问来源于stack exchange,提问作者Daniel Shwa
相关产品推荐
相关产品推荐

