C語言再學習之記憶體對齊

2022-07-04 03:24:15 字數 2005 閱讀 7153

昨天看q3的**,看到有個_intsaizeof的巨集,著實暈了一陣。一番google後,終於明白,這個巨集的作用是求出變數占用記憶體空間的大小,先看看_intsaizeof的定義吧:

#define _intsizeof(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

(ansi c標準下,_intsaizeof巨集定義在stdarg.h中,q3中定義在bg_lib.h中;bg_lib.h -- standard c library replacement routines used by code)

關於這個巨集的內部原理,我們後面再談,還是先理理「記憶體對齊」這詞的意思吧,多年來一直模糊的存在於我的大腦中,究竟為什麼要記憶體對齊啊。

記憶體對齊的根源

1、許多計算機系統對基本資料型別可允許位址作了一定的限制,要求某種型別物件的位址必須是某個值n(通常是2、4、8)的倍數,從而來簡化處理器和儲存器之間的介面的硬體設計。如linux的對齊策略是2位元組資料型別,例如short的位址必須是2的倍數。而較大的資料型別如:int、int*、float、double則必須是4的倍數。而microsoft windows的策略要求更為嚴格-----任何k位元組物件的位址必須是k的倍數。比如要求乙個double型別物件的位址必須是8的倍數(引自《深入理解計算機系統》)。

2、資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。

記憶體對齊的規則

上面所提到的自然邊界是由什麼決定的呢,我想應該是由硬體平台決定的,至於作業系統和編譯器(預設對齊係數)則都是依賴於上一層的。當然,編譯器的對齊係數可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16來改變;

舉個例子:比如引數入棧,編譯器並不是乙個緊挨著乙個的壓入棧的,而是根據對齊係數來壓棧的,比如乙個char型別的引數,雖然本身只佔乙個位元組,但是編譯器會自動補全後面3個位元組,然後再壓下乙個引數。

(這裡說點題外話:在寫過delphi程式的人都知道,有個packed的保留字,作用就是壓縮資料結構,不要按對齊儲存,除非資料結構體積龐大,否則為什麼要用packed呢,用了不就影響記憶體讀取的速度了嗎?:))

1、資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。 

2、結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。 

3、結合1、2顆推斷:當#pragma pack的n值等於或超過所有資料成員長度的時候,這個n值的大小將不產生任何效果。

(以上3點引自《也談記憶體對齊》一文)

再看_intsaizeof巨集

這個巨集的定義咋一看有點丈二和尚摸不著頭腦,不過網上有對齊的解釋,看後相信會豁然明朗了:

對於兩個正整數 x, n 總存在整數 q, r 使得 

x = nq + r, 其中  0<= r 0, 取 (q+1)n. 這也相當於把 x 表示為: 

x = nq + r', 其中 -n < r' <=0                //最大非正剩餘 

nq 是我們所求。關鍵是如何用 c 語言計算它。由於我們能處理標準的帶餘除法,所以可以把這個式子轉換成乙個標準的帶餘除法,然後加以處理: 

x+n = qn + (n+r'),其中 0x+n-1 = qn + (n+r'-1), 其中 0<= n+r'-1 所以 qn = [(x+n-1)/n]n. 用 c 語言計算就是: 

((x+n-1)/n)*n 

若 n 是 2 的方冪, 比如 2^m,則除為右移 m 位,乘為左移 m 位。所以把 x+n-1 的最低 m 個二進位制位清 0就可以了。得到: 

(x+n-1) & (~(n-1))

C語言結構體之記憶體對齊

首先看乙個例子,下面有乙個結構體 struct structtest1 假設這個結構體成員在記憶體中是緊湊排列的,那麼c1的儲存位址就是0,s的儲存位址是1 2,c2的儲存位址是3,i的儲存位址是4 7,c1的位址是0000000000000000,s的位址是0000000000000001,c2的...

C 深陷 之「記憶體對齊」

現代計算機在處理資料時,按照某個 單位 來處理。32位機器,每次處理32位 4位元組的二進位制資料,64位同理。記憶體對齊指的是計算機系統對基本資料型別合法位址做出了一些限制,要求某種型別物件的位址必須是某個值的倍數。本文著重於記憶體對齊的基本原理,有關複雜情況下 虛函式 繼承等 的記憶體對齊方案,...

編譯之 記憶體對齊

現代計算機中記憶體空間都是按照 byte 劃分的,也就是位元組,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊 從cpu的角度來說,cpu...