内存对齐宏NGX_ALIGN的解释


内存对齐的一个宏:#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))

以前对于这个宏有讨论过,不过似乎都讲得很模糊,作为一个知识点不应该有模糊
这个宏的目的是:将地址值调整为下一个边界上。
先问问自己:我应该怎么去实现这个功能呢?
假设: addr = 0xbfdf8cf3        也就是:1011 1111 1101 1111 1000 1100 1111 0011
那么:如果我要将这个值调整到下一个2字节边界上
      就应该是:xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx10
         也就是2的倍数上。
      如果我要将这个值调整到下一个4字节边界上
      就应该是:xxxx xxxx xxxx xxxx xxxx xxxx xxxx x100 
      也就是4的倍数上。
      最后,如果我要将这个值调整到下一个8字节界边上
      就应该是:xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1000
         也就是8的倍数上
怎么做呢? 我必须根据所要调整边界的要求 将 addr 的低几位置 0,同时还要增加一个 模值
例如:我要将 addr 调整到 4 字节界上,于是我就有一个初步的想法
1、addr 加上 0100 使它跳到下一个 4 字节
    addr + 0000 0000 0000 0000 0000 0000 0000 0100
      结果为:1011 1111 1101 1111 1000 1100 1111 0111
2、将上一步的结果低 2 位清 0,从而实现调整要求
   1011 1111 1101 1111 1000 1100 1111 0111 
&  1111 1111 1111 1111 1111 1111 1111 1100
--------------------------------------------------------------
    1011 1111 1101 1111 1000 1100 1111 0100
3、1111 1111 1111 1111 1111 1111 1111 1100 怎么通过 4 运算得出来呢?
    负数:-4 在机器中表示为: -4 = ~4 + 1
              即: 1111 1111 1111 1111 1111 1111 1111 1011        =  ~4
                  + 0000 0000 0000 0000 0000 0000 0000 0001        =  1
                 -----------------------------------------------------------------------------
                     1111 1111 1111 1111 1111 1111 1111 1100        =  -4
   
4 、总结一下,得出以下算法
    (addr + align_size) & (-align_size)
所以:我可以这样定义这个宏
#define PAGE_ALIGN(addr, align_size)  ((addr+align_size) & (-align_size))
而后来:我发现,只要加上被清0位数上的最大值,就可以跳到下一个对齐边界上,
        也就是: 4 字节对齐时,只要加上3就可以了,
                 8 字节对齐时,只要加上7就可以了,
                 2 字节对齐时,只要加上1就可以了,

            即: addr + align_size - 1 就可以了 !!!
        下一步做 & 时:4字节对齐,只要将 3 取反就得出 0xFFFF FFF4
                                   8字节对齐,只要将 7 取反就得出 0xFFFF FFF8
                                   2字节对齐,只要将 1 取反就得出 0xFFFF FFF2
    于是: 我就有了算法的另一个版本:
       ( addr + align_size - 1 ) & (~(align_size - 1))       
最后, 我就可以将宏定义为:       
#define PAGE_ALIGN(addr, align_size) ((addr+align_size-1) & ~(align_size-1))
也就是,LZ 所问的宏是怎么来的

补充一点:

(addr + align_size) & (-align_size)

这个算法,忽略了对 低几位是 0 的情况的考虑!

如果:xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx00 
这种情况的话 addr + align_size 导致空跳到下一边界
addr + align_size - 1 无论什么情况下都是正确的。

-align_size 与 ~ (align_size - 1) 本质上是一样的, 而 - align_size 似乎更好理解,建议采用这种形式 

发布了40 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/suoyudong/article/details/90051131
今日推荐