((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))的含義

  • 微信公衆號:鄭爾多斯
  • 關注「鄭爾多斯」公衆號 ,回覆「領取資源」,獲取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,若是AB至少有一個是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)/M2中的分步討論結果一致。
可能有的讀者還會問,這個公式是怎麼想出來的,怎麼就想到了加上那個M-1?
這個問題能夠先去看看數論中的餘數理論。app

5、對齊代碼的分析
有了上面的數學基礎,咱們再來看看開頭所說的對齊代碼的含義
((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))
意義就很明顯了
這裏。機器字長度sizeof(int)至關於箱子的容量M, 變量的真實字節 sizeof(n) 大小相於貨物總數N,整個代碼就是求n所佔的機器字數目。ui

順便仔細的解釋一下
~(sizeof(int)-1))
這裏用到了一個位運算的技巧,即若M2的冪,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長度的整數倍。
好比n5,二進制就是101bint長度爲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



喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達
鄭爾多斯
鄭爾多斯
相關文章
相關標籤/搜索