- 微信公衆號:鄭爾多斯
- 關注「鄭爾多斯」公衆號 ,回覆「領取資源」,獲取IT資源500G乾貨。
升職加薪、當上總經理、出任CEO、迎娶白富美、走上人生巔峯!想一想還有點小激動- 關注可瞭解更多的
Nginx
知識。任何問題或建議,請公衆號留言;
關注公衆號,有趣有內涵的文章第一時間送達!
在nginx
的代碼中常常出現相似((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))
的代碼,這部分代碼的做用是什麼呢?本文分析一下它的神奇之處。
本文主要參考文章末尾的兩個連接,並稍做整理。html
先看一個平常生活中的問題,
問題1:假設有要把一批貨物放到集裝箱裏,貨物有12件,
一個箱子最多能裝6
件貨物,求箱子的數目。
解答:顯然咱們須要12 / 6 = 2
個箱子,而且每一個箱子都是滿的。這個連小學生都會算:-)
問題2: 把問題1的條件改一下,假設一個箱子最多能裝5
件貨物,那麼如今的箱子數是多少?
解答:12/5=2.4
個,可是根據實際狀況,箱子的個數必須爲整數,(有不知道這個常識的就不要再往下看了,回小學重讀吧,哈哈)天然咱們就要取3
,
下面把問題通常化nginx
問題3:設一個箱子最多能夠裝M件貨物,且現有N件貨物,
則至少須要多少個箱子,給出通常的計算公式。
這裏要注意兩點
一、箱子的總數必須爲整數
二、N
不必定大於M
,很顯然,很顯然,即便N ≤ M
,也須要一個箱子微信
一、預備知識
在討論之問題3的解答以前,咱們先明確一下/
運算符的含義。
定義/
運算爲取整運算,即
對任意兩個整數N,M,必然有且只有惟一的整數X
,知足X * M <= N < (X + 1) * M
,那麼記N / M=X
。
這個也正是c語言
裏/
運算的確切含義。x的存在性和惟一性的嚴格證實能夠見數論教材。
之後如無額外說明, / 運算的含義均和本處一致。
/ 運算有一個基本的性質
若N=MX+Y
,則N/M = X+Y/M
,證實略
注意:N
不是能夠隨便拆的,設N= A + B
,那麼通常狀況下N/M
不必定等於A/M + B / M
,若是A
和B
至少有一個是M
的倍數,才能保證式子必定成立。
二、分步討論
根據上面的/
運算符的定義,咱們能夠獲得問題三的解答,分狀況討論一下
已知N/M=X
,那麼當
(1)、當N
正好是M的倍數時即N=M*X
時,那麼箱子數就是X=N/M
(2)、若是N
不是M
的倍數,即N=M*X+Y
(1 <=Y < M
那麼顯然還要多一個箱子來裝餘下的Y
件貨物 ),則箱子總數爲X+1 = N/M+1
三、通常公式
上面的解答雖然完整,可是用起來並不方便,由於每次都要去判斷N和M的倍數關係,
咱們天然就要想一個統一的公式,因而,下面的公式出現了
箱子數目爲 ( N + M - 1) / M
.
這個式子用具體數字去驗證是很簡單的,留給讀者去作。
我這裏給一個完整的數學推導:
如今已經假定/
運算的結果爲取整(或者說取模),即N/M=X,則XM <= N <(X+1)M
那麼,
(1)、當N=MX
時,(N+M-1)/M = MX/M + (M-1)/M = X
(2)、當N=MX+Y(1 <=Y < M)
時,
因爲 1 <=Y < M
, 同時加上M-1
,獲得 M <= Y + M - 1 < 2M-1 < 2M
根據 /
運算的定義 (Y + M - 1) / M = 1
因此 (N+M-1) / M = (MX+Y+M-1)/M= MX / M+(Y+M-1) / M= X+1
顯然 公式 (N+M-1)/M
與2
中的分步討論結果一致。
可能有的讀者還會問,這個公式是怎麼想出來的,怎麼就想到了加上那個M-1
?
這個問題能夠先去看看數論中的餘數理論。app
5、對齊代碼的分析
有了上面的數學基礎,咱們再來看看開頭所說的對齊代碼的含義((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))
意義就很明顯了
這裏。機器字長度sizeof(int)
至關於箱子的容量M
, 變量的真實字節 sizeof(n)
大小相於貨物總數N,整個代碼就是求n
所佔的機器字數目。ui
順便仔細的解釋一下~(sizeof(int)-1))
這裏用到了一個位運算的技巧,即若M
是2
的冪,M=power(2,Y)
;
則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)。spa
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) – 1) & ~(sizeof(int) – 1)
[此問題的推薦答案]~
是位取反的意思。_INTSIZEOF(n)
整個作的事情就是將n
的長度化爲int
長度的整數倍。
好比n
爲5
,二進制就是101b
,int
長度爲4
,二進制爲100b
,那麼n
化爲int
長度的整數倍就應該爲8
。~(sizeof(int) – 1) )
就應該爲~(4-1)=~(00000011b)=11111100b
,這樣任何數& ~(sizeof(int) – 1) )
後最後兩位確定爲0
,就確定是4
的整數倍了。(sizeof(n) + sizeof(int) – 1)
就是將大於4m
但小於等於4(m+1)
的數提升到大於等於4(m+1)
但小於4(m+2)
,這樣再& ~(sizeof(int) – 1) )
後就正好將原長度補齊到4
的倍數了。.net
((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))邊界對齊
& ~(sizeof(int) - 1) )詳解unix