用C語言寫程序時須要知道是大端模式仍是小端模式。 程序員
所謂的大端模式,是指數據的低位保存在內存的高地址中,而數據的高位,保存在內存的低地址中;所謂的小端模式,是指數據的低位保存在內存的低地址中,而數據的高位保存在內存的高地址中。數組
爲何會有大小端模式之分呢?這是由於在計算機系統中,咱們是以字節爲單位的,每一個地址單元都對應着一個字節,一個字節爲8bit。可是在C語言中除了8bit的char以外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對於位數大於8位的處理器,例如16位或者32位的處理器,因爲寄存器寬度大於一個字節,那麼必然存在着一個若是將多個字節安排的問題。所以就致使了大端存儲模式和小端存儲模式。例如一個16bit的short型x,在內存中的地址爲0x0010,x的值爲0x1122,那麼0x11爲高字節,0x22爲低字節。對於大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x2211中。小端模式,恰好相反,仍是ox1122。咱們經常使用的X86結構是小端模式,而KEIL C51則爲大端模式。不少的ARM,DSP都爲小端模式。有些ARM處理器還能夠由硬件來選擇是大端模式仍是小端模式。數據結構
Java、.NET大行其道的今天,C語言做爲一門經典的高級語言,存在的惟一理由就是其高效、精練。隨着PC硬件升級和降價,C語言因爲其自身的複雜度,在開發PC應用軟件時,已經不多使用。可是在開發嵌入式系統軟件和操做系統時,因爲廣泛強調微內核,少佔用空間和高效,所以,在系統開發舞臺上,C語言依舊是主角。函數
在實際的程序開發中,爲了提升數據的讀取效率,在內存資源足夠的狀況下,通常在定義數據結構時,應該考慮四字節對齊,其緣由很簡單,如今的計算機多數是32位,也就是四字節。在每次讀取數據時,通常都是直接讀取32位的數據。有些狀況下,字節對齊的數據結構,要比非對齊的數據結構佔用空間少。如下分別就這兩方面舉例闡述。
一、充分考慮四字節對齊,能夠節省存儲空間
typedef struct tagAAA{
char name[10];
long sno;
char sex;
float score[4];
}AAA;
typedef struct tagBBB{
char name[10];
char sex;
long sno;
float score[4];
}BBB;
在VC下,調試,能夠很容易看出來,AAA佔的存儲空間爲36,BBB佔的存儲空間爲32。緣由很簡單,在四字節對齊的狀況下,按四個字節爲單位分配存儲空間,若是不足,會自動補充,本次分配不足以存放下面的變量時,會從新分配空間。
AAA:
|name[0]|name[1]|name[2]|name[3]|
------------------------------------
|name[4]|name[5]|name[6]|name[7]|
------------------------------------
|name[8]|name[9]| | |
----------因爲剩下的兩個字節不足以存放sno(long佔四個字節),因此從新分配
------------------------------------
| sno |
----------long變量佔四個字節,32bits
------------------------------------
|sex | 自動填充 |
----------剩餘三個字節的空間,不足以重放一個float變量,所以從新分配
------------------------------------
| score[0] |
------------------------------------
| .......... |
------------------------------------
| score[3] |
------------------------------------
由此能夠輕易的計算出,AAA佔36個字節,同理,很容易計算出BBB佔32個字節空間。
二、字節對其的狀況下,能夠更高效的訪問
假設一個結構體的數據以下存儲:
-----------------------------------------------------
| 12 | 34 | 56 | 78 | -----------(A)
-----------------------------------------------------
-----------------------------------------------------
| XX | YY | 12 | 34 | -----------(B)
-----------------------------------------------------
| 56 | 78 | XX | YY |
在A狀況下,一次性讀取數據成功,可是,在B狀況下,須要讀取數據兩次,由此,可看出效率的差別。
通常狀況下,字節對齊聽從系統字節數與要求的對齊字節數相比,最小原則,即:假設要求按八字節對齊,可是系統爲32位系統,則按照4字節對齊。在四字節對齊時,局部會按照2字節對齊,如:
struct tagAAA
{
char a;
short b;
char c;
}AAA;
該結構體佔據的空間爲8字節而不是4字節,緣由就是:
-----------------------------------
| a | | b |
-----------------------------------
| c | |
而不是:
------------------------------------
| a | b | c |
------------------------------------
其緣由就是局部會以2字節對齊。
***********************************************
衆所周知,C語言程序設計中,內存的分配和管理徹底交由程序員來控制,所以,內存管理是每一個C程序員必須熟練掌握的。通常而言,分配給進程的內存有四個概念上不一樣的區域,分別爲:代碼段、數據段、堆和棧,其中數據段又能夠細分爲初始化爲非零的數據和初始化爲零的數據。以下圖所示:
-------------------
| 程序棧 |----------高地址--〉低地址(向下增加)
-------------------
| 堆 |----------向上增加
-------------------
| BSS |----------數據段
| 全局和靜態變量 |
-----------------------------低地址
| 可執行代碼 |----------代碼段
-------------------
可執行指令放在代碼段中,任什麼時候刻,內存中只有一份相同程序的指令拷貝,多個實例共享這些代碼。
初始化爲非零的靜態數據和全局數據存放在數據段中,運行相同程序的每一個進程,有本身的數據段。
初始化爲零(即未初始化的變量,系統自動填充爲0;或者初始化爲0)的全局數據和靜態分配數據存放在進程的BSS區域中,每一個運行的進程都有本身的BSS,程序運行的時候,將數據放到數據段中,由此可知,只有初始化爲非零的變量才佔用空間,因此對於相似static int ss[1024];這樣的數組自動用0來填充,它佔的空間很小。
【BSS是「Block Started by Symbol」的縮寫,意爲「以符號開始的塊」。BSS是Unix連接器產生的未初始化數據段。其餘的段分別是包含程序代碼的「text」段和包含已初始化數據的「data」段。BSS段的變量只有名稱和大小卻沒有值。此名後來被許多文件格式使用,包括PE。「以符號開始的塊」指的是編譯器處理未初始化數據的地方。BSS節不包含任何數據,只是簡單的維護開始和結束的地址,以便內存區能在運行時被有效地清零。BSS節在應用程序的二進制映象文件中並不存在,例如:
unsigned char var; // 分配到.bss節的8位未初始化變量
unsigned char var2 = 25; // 分配到.data節的8位已初始化變量
】
堆,動態內存來自於堆,即:經過malloc獲得的空間,一般狀況下,堆是向上增加的,即:後面分配的地址比前面的地址在數值上大一些。
【注意:這裏的堆並非數據結構中的堆,它的分配方式相似於鏈表】
棧,分配局部變量的地方,函數參數、函數的返回值和返回地址也放在棧空間中,須要特別注意的是,當函數返回後,存儲在棧空間中的函數變量「自動消失」,空間被其餘函數使用。棧空間是向下增加的。
在C語言中,通常經過malloc/calloc函數分配空間,經過free()函數釋放空間,使用realloc()改變已分配空間的大小。
分配內存的步驟:
1.申明一個指定類型的指針
2.計算要分配空間的大小,通常使用函數sizeof()來實現
3.調用函數malloc()完成空間的申請,將函數的返回值賦給指針變量,
4.檢查返回值是否不爲NULL,保證空間分配成功
5.分配好的空間是沒有通過初始化的,其中可能包含一些垃圾信息,所以調用函數memset()將其用0來填充是個好的習慣
釋放內存步驟:
1.調用函數free()釋放掉空間
注意:
1.不可使用free()以後的空間
2.free()後,最好將指針置爲NULL,由於若是不作這步處理,
原來的指針依舊指向剛纔釋放的空間,能夠繼續操做
3.避免重複釋放空間
在Unix系統上,提供了函數alloca()函數,能夠實如今棧空間上分配指定大小的空間,這樣的好處是,函數結束後,空間自動釋放,沒必要顯式地調用函數free(),可是該函數有不少弊端,好比不可移植等,所以不建議使用。
有必要提一下malloc、calloc、realloc函數的底層實現,在Linux系統中,提供了brk()和sbrk()函數,上面幾個函數就是在這兩個函數的基礎上實現的。