看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的余數。
故得證。