关于一段地址对齐的位运算代码的解释

http://blog.csdn.net/aihao1984/article/details/5953668这篇博文讲C的函数可变参数时,发现了以下用于做地址对齐的这段代码:

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) //为了满足需要内存对齐的系统

这段代码做的事情就是,给定一个变量n,算出这个变量对齐到某个字长(整型的字节数)整数倍的字节数。这段代码有些难以理解。那么慢慢分析下吧。

假设有一个地址n,要把n按m对齐,无非就是找到大于等于n且整除m的最小的那个数

我们定义一个宏函数F,它计算n按m对齐的结果,则按照上段代码的逻辑,F定义为:

#define F(n, m) (n+m-1)&~(m-1)

这段代码如果不用这种按位与来写,其实可以这么写:

#define F(n, m) (n+m-1)/m*m

以上的做法正确性可以分情况证明:

为了说明问题方便,由于计算机里的除法和严格的数学意义上的除法是不一样的,我们这里以"/"表示计算机里的除法,"%"表示严格的数学除法,"mod"表示取模运算。之后也遵循这个惯例,只是代码还是遵循计算机语言本身的规范。

1.如果n是能整除m,那么对齐结果应该就是n,能得出F(n, m)的结果正确;

2.如果n不能整除m,那么对齐结果应该是n - n mod m + m。由于n - n mod m + m能整除m,所以我们只需要证(n - n mod m + m)/m等于(n+m-1)/m。也即证

  0<= (n+m-1) - (n - n mod m + m) < m

上面这个式子很显然。

当我们再审视计算机里的除法"/"时,发现,实际上,对于整数x与y,有:

  x/y = (x - x mod y) % y

设a=n+m-1,有

  (n+m-1)/m*m = a/m*m = (a - a mod m)%m*m = a - a mod m

实际上,只要证

  a&~(m-1) = a - a mod m

当然,这里的前提是,m是2的幂次(因为m是整型的字节数,即字长)。

这里假设m=2^q。那么m的二进制表示一定是1后面跟q个0。m-1则为最后面q位为1,前面全为0,按位取反结果是后面q位为0,前面为1。

由于m是2的幂次,故a mod m结果就是a的二进制表示的最后q位结果。而a按位与一个前面全为1后q位为0的二进制数,则正好就是减去了后q位,等同于减去a对m的余数。

故得证。

posted @ 2014-11-19 23:40  waytofall  阅读(2820)  评论(1编辑  收藏  举报