聽到好幾個朋友說到去一些公司做面試,總是遇到關於大小端、位段(或者叫位域)和記憶體對齊的考題,然後就不知所措了。雖然我認為很多開發根本就用不到這個,但是我認為很有必要學習理解這些知識點,因為它可以讓你更了解c++的,了解程式在記憶體的運**況,也能加深對計算機系統的理解。
宣告:由於本文的**會受到計算機環境的影響,故在此說明本篇博文中的程式的執行環境。
1、microsoft windows 7 ultimate edition service pack 1 (64bit 6.1.7601)
2、microsoft visual studio 2010 version 10.0.40219.1 sp1rel(ultimate--enu)。
3、microsoft .net framework version 4.0.30319 sp1rel
4、microsoft visual c++ 2010
注:雖然系統是64位的,但是我是使用vc++ 2010預設配置,也即是x86平台。所以下面所有示例和文字表述都是基於32位編譯平台。
在現代「馮.諾依曼體系結構」計算機中,它的數制都是採用二進位制來儲存,並且是以8位,乙個位元組為單位,產生記憶體位址系統。資料在記憶體中有如下三種存在方式:
1、從靜態儲存區分配:此時的內存在程式編譯的時候已經分配好,並且在程式的整個執行期間都存在。全域性變數,static變數等在此儲存。
2、在棧區分配:在程式的相關**執行時建立,執行結束時被自動釋放。區域性變數在此儲存。棧記憶體分配運算內置於處理器的指令集中,效率
高,但容量有限。
3、在堆區分配:動態分配記憶體。用new/malloc時開闢,delete/free時釋放。變數的生存期由使用者指定,靈活,但會有記憶體洩露等問題。
對於像c++中的char這樣的資料型別,它本身就是占用乙個位元組的大小,不會產生什麼問題。但是當數制型別為int,在32bit的系統中,它需要占用4個位元組(32bit),這個時候就會產生這4個位元組在暫存器中的存放順序的問題。比如int maxheight = 0x12345678,&maxheight = 0x0042ffc4。
具體的該怎麼存放呢?這個時候就需要理解計算機的大小端的原理了。
大端:(big-endian)就是把數值的高位位元組放在記憶體的地位位址上,把數值的地位位元組放在記憶體的地位位址上。
小端:(little-endian)就是把數字的高位位元組放在高位的位址上,地位位元組放在地位位址上。
我們常用的x86結構都是小端模式,而大部分dsp,arm也是小端模式,不過有些arm是可以選擇大小端模式。所以對於上面的maxheight是應該以小端模式來存放,具體情況請看下面兩表。
位址0x0042ffc4
0x0042ffc5
0x0042ffc6
0x0042ffc7
數值0x78
0x56
0x34
0x12
上圖為小端模式
位址0x0042ffc4
0x0042ffc5
0x0042ffc6
0x0042ffc7
數值0x12
0x34
0x56
0x78
上圖為大端模式
通過上面的**,可以看出來大小端的不同,在這裡無法討論那種方式更好,個人覺得似乎大端模式更符合我的習慣。(注:在這裡我還要說一句,其實在計算機記憶體中並不存在所謂的資料型別,比如char,int等的。這個型別在**中的作用就是讓編譯器知道每次應該從那個位址起始讀取多少位的資料,賦值給相應的變數。)
在前面已經提起過,在計算機中是採用二進位制0和1來表示資料的,每乙個0或者1占用1位(bit)儲存空間,8位組成乙個位元組(byte),為計算機中資料型別的最小單位,如char在32bit系統中占用乙個位元組。但是正如我們知道的,有時候程式中的資料可能並不需要這麼的位元組,比如乙個開關的狀態,只有開和關,用1和0分別替代就可以表示。此時開關的狀態只需要一位儲存空間就可以滿足要求。如果用乙個位元組來儲存,顯然浪費了另外的7位儲存空間。所以在c語言中就有了位段(有的也叫位域,其實是乙個東西)這個概念。具體的語法就是在變數名字後面,加上冒號(:)和指定的儲存空間的位數。具體的定義語法如下:
1: struct 位段名稱 2: 6: 7: 例項 8: 9: struct node 10: node;
其實定義很簡單,上面示例的意義是,定義乙個char變數a,占用2位儲存空間,乙個double變數i,以及乙個占用4位儲存的int變數c。請注意這裡改變了變數本來占用位元組的大小,並不是我們常規定義的乙個int變數占用4個位元組,乙個char變數占用1乙個位元組。但是sizeof(node) = ?呢,在實際的執行環境中執行,得到sizeof(node) = 24;為什麼呢?說起來其實也很簡單,位元組對齊,什麼是位元組對齊,待會下乙個段落會具體講解。先來看乙個面試示例,**如下:
1: #include 2: 3: usingnamespace std; 4: 5: union 6: s; 13: 14: char ch; 15:}r; 16: 17: int _tmain(int argc, _tchar* argv)18: __attribute__((packed))a;
大小端 位域
小端 低位 lsb 位於低位址 大端 高位 msb 位於低位址 x86一般使用小端模式 位域 typedef union liteu32 t test t 位域的分配 小端 從lsb msb,從低位址到高位址 大端 從msb lsb,從高位址到低位址 例如 test t tt tt.t 0x3f p...
大小端,位域
大小端是指資料在記憶體中存放的順序,大於乙個位元組的整數,在記憶體中低位元組在前的就是小端,高位元組在前的就是大端。用c語言程式來判斷大端機還是小端機 include int main 位域 位域是指資訊在儲存時,並不需要占用完整的位元組,只需要占用幾個二進位制位。位域就是把乙個位元組中的二進位制位...
bit 位域大小端轉換問題
由於不同的計算機系統可能存在不同的大小端模式,所以不同的體系系統間通訊就需要進行大小端轉換。任何在不同系統間的通訊資訊都經過網路位元組 大端 序進行傳輸,也就是說不管本機是什麼模式,都要保證傳送端傳輸的資料轉換為網路序,接受端都要把網路序的資料轉換為本地序。16bit和32bit的大小端轉換很常見,...