一、問題的提出
兩年之前我寫過一篇可變引數學習筆記,裡面曾經簡單的解釋過一句:
** ((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))
的作用是在考慮位元組對齊的因素下計算第乙個可變引數的起始位址。
當時限於時間和水平,未能做更詳細的解釋。
今天(2007-11-26)在csdn論壇上看到了乙個帖子
問題:crt原始碼分析中乙個關於可變函式引數的問題
提問者:sun_moon_stars
裡面又問到了這個巨集,於是決定抽出半天時間,把這個問題詳細的說清楚。也算是把我的那篇文章
做乙個完美的結尾。
二、引子
先看乙個日常生活中的問題,
問題1:假設有要把一批貨物放到貨櫃裡,貨物有12件,
乙個箱子最多能裝6件貨物,求箱子的數目。
解答:顯然我們需要12/6=2個箱子,並且每個箱子都是滿的。這個連小學生都會算:-)
問題2: 把問題1的條件改一下,假設乙個箱子最多能裝5件貨物,那麼現在的箱子數是多少?
解答: 12/5=2.4個,但是根據實際情況,箱子的個數必須為整數,(有不知道這個常識的就不要再往下看了,
回小學重讀吧,呵呵)自然我們就要取3,
下面把問題一般化
三、一般數學模型
問題3:設乙個箱子最多可以裝m件貨物,且現有n件貨物,
則至少需要多少個箱子,給出一般的計算公式。
這裡要注意兩點
1、箱子的總數必須為整數
2、n不一定大於m,很顯然,即使n 則n/m = n>>y ,
另根據數論中的餘數定理,
有n=m*x+z(1 < =z < m)
而注意到這裡的n,m,z都是二進位制表示,所以把n的最右邊的y位數字就是餘數z.
剩下的左邊數字就是模x.
而記憶體對齊要計算的是占用的總位元組數(相當於箱子的最大容量),所以
總位元組數 = ( n/m)*m =( n>>y)《注意,這裡的右移和左移運算並未相互抵消,最後的結果實際上是把n中的餘數z去掉(被清0),
而左邊模x得以保持不變。
而當m = power(2,y) 時
(n >>y) << y = (n &(~(m-1))也是乙個恒等式(這個讀者也可以用數字驗證),
所以,就得到我們前面看到的巨集
((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))
注意:
(1)這裡最關鍵的一點就是m必須是2的冪(有人常常理解成2的倍數也可以,那是不對的),
否則上面的結論是不成立的
(2) ~(m-1)更專業的叫法就是掩碼(mask)。因為數字和這個掩碼進行與運算後,數字的最右邊y位的
數字被置0("掩抹"掉了).即掩碼最右邊的0有多少位,數字最右邊就有多少位被清0。
小結:
1、位元組對齊的數學本質就是數論中的取模運算。在計算機上的含義就是求出乙個物件占用的機器字數目。
2、在數學上看記憶體計算的過程就是先右移再左移相同的位數,以得到箱子的最大容量。
3、在c中/運算可以用位運算和掩碼來實現以加快速度(省掉了求位數的過程),前提是機器字長度必須為2的冪。
關於記憶體對齊
資料傳送到網路板的資料報大小根本不是實際控制數 據包的大小 這時我才想起乙個人,stanley b.lippman,他寫的那 一本書 inside object modale 曾經提過這樣的事 情,編譯器為了提高cpu的效率,會對struct 的結構進行優化,利用sizeof 可以得出不同的計算機上...
關於記憶體對齊
早上看了乙個貼的面試題,struct st int i short s char c sizeof struct st 是多少?int 4,short 2,char 1,但是sizeof st 是8。這個就是記憶體對齊 再來看個例子 struct strt1 strt1 s1 假設s1.c1位址為0...
關於記憶體對齊
資料傳送到網路板的資料報大小根本不是實際控制資料報的大小 這時我才想起乙個人,stanley b.lippman,他寫的那一本書 inside object modale 曾經提過這樣的事情,編譯器為了提高cpu的效率,會對struct 的結構進行優化,利用sizeof 可以得出不同的計算機上對 s...