1. 程式人生 > >資料在記憶體中的儲存總結

資料在記憶體中的儲存總結

資料型別介紹:

基本內建型別分別為:

char         //字元資料型別
short        //短整型
int          //整形
long         //長整型
long long    //更長的整形
float        //單精度浮點數
double       //雙精度浮點型

//注意: C語言中沒有字串型別

 

型別的意義:

1. 使用這個型別開闢的記憶體空間大小(大小決定了適用範圍)。

2. 如何看待記憶體空間的視角。

在32位平臺下,任何指標型別都只佔4個位元組。

 

型別的歸類:

整形家族:

char 
        unsigned char
        signed char

short
        unsigned short [int]
        signed short [int]

int
        unsigned int
        signed int

long
        unsigned long [int]
        signed long [int]

浮點數家族:

float

double

構造型別:

> 陣列型別

> 結構體型別 struct

> 列舉型別 enum

> 聯合型別 union

指標型別 空型別:

void 表示空型別(無型別)通常應用於函式的返回型別、函式的引數、指標型別。

注意:

1. void 是型別,不能定義變數,空型別對應的大小是0,。所以 void 無法開闢空間,即無法定義變數。

2. 雖然 void 在linux 系統下大小為 1 個位元組,但是系統認定 void 為空型別,同樣無法定義變數。

3. 雖然 void 不能定義變數,但是 void* 可以,在 32 為平臺下,任何指標的大小都是4個位元組,但是不能解引用。

4. C 語言中函式的返回值型別可以省略,但是省略之後預設為 int。

5. void* 可以接收任何型別。

 

 整形在記憶體中的儲存:

一個變數建立是要在記憶體中開闢空間的。空間的大小是根據不同的型別而決定的。

在知道整形怎麼儲存之前,我們先引入

原碼、反碼、補碼。

計算機中的符號數有三種表示方法,即原碼、反碼和補碼。三種方法均有符號位和數值位兩部分,符號位 0 表示正數, 符號位 1 表示負數,而數值位,三種表示方法各不相同。
 

原碼:直接將二進位制按照正負數的形式翻譯成二進位制就可以了。

反碼:

將原碼的符號位不變,其他位依次按位取反就可以得到了。

補碼:反碼 +1 就得到補碼。

正數的原碼、反碼、補碼相同。  

對整形來說:資料存放記憶體中其實存放的是補碼。

這樣也是有原因的:

1. 使用補碼,可以將符號位和數值域統一處理;

2. 加法和減法也可以統一處理(CPU只有加法器);

3. 補碼與原碼相互轉換,其運算過程是相同的,不需要額外的硬體電路。

先來看看整形在記憶體中儲存的例子:

我們先定義兩個變數:

int a = 20;
int b = -10;

然後看看他們在記憶體中是如何存的。

變數a在記憶體中的儲存:

因為a為正數,所以在儲存的時候先將十進位制數,轉化為二進位制數原碼,並且因為是正數,所以原、反、補碼相同,不用轉化。

變數b在記憶體中的儲存:

因為b為負數,在進行十進位制轉化為二進位制原碼後,要進行原碼和補碼之間的轉化,轉化過程為符號位不變其他位按位取反,再加一。

可是有沒有覺得怪怪的?為什麼數字是反過來排列的?難道不是應該是 00 00 00 14 和 ff ff ff f6 嗎?

這裡就要引入小端儲存和大端儲存。

資料是有高、低位之分的,記憶體地址是有高、低地址之別的。

小端儲存模式:是指資料的低位儲存在記憶體的低地址中;

上圖就是小端儲存,儲存的方式是

 

 

大端儲存模式:是指資料的低位儲存在記憶體的高地址中。

與小端儲存一樣,只是反過來,將低位資料儲存在高地址中,這裡不再贅言。

 

浮點數在記憶體中的儲存:
 

我們先看一個列子:

int main(void)
{

	int n = 9;
	float *pFloat = (float *)&n;
	printf("n -> %d\n", n);
	printf("pFloat -> %f\n", *pFloat);

	*pFloat = 9.0;
	printf("n -> %d\n", n);
	printf("pFloat -> %f\n", *pFloat);
    
        system("pause");
	return 0;
}

這個程式的輸出是:

為什麼呢??????

只要我們瞭解了浮點數在記憶體中是如何儲存的,這個問題就很好解決!

1. 根據國際標準IEEE 754,任意一個二進位制浮點數V可以表示成下面的形式:
 ·  (-1)^S * M * 2^E。

 ·  (-1)^S 表示符號位,當S == 0, V為正數;當S == 1, V為負數。

 ·  M表示有效數字,大於等於1,小於2、

 ·  2^E表示指數位。

舉個例子:十進位制的5.0,轉化成二進位制就變成了101.0,用科學計數法表示就是 1.01 * 2^2 。那麼,按照上面V的格式,可以得出S = 0, M = 1.01,E = 2 。

                  如果是-5.0,S = 1, M = 1.01, E = 2 。

2. IEEE 754規定:對於32位浮點數,最高的1位是符號位S, 接著的8位是指數E,剩下的23位為有效數字M。

E和M的儲存方式也是IEEE 754的規定,記住就好。

對於64位浮點數,最高的1位是符號位S,接著的11位是指數E,剩下的52位為有效數字M。

圖跟上圖32位類似,這裡就不畫了。

E的兩種特殊取值:

1. E全為0:

    當E全為0的時候,即2的次方為0 - 127 為2^-127次方,所以,當s = 0時,一個正數的2^-127次方,是一個從數軸的右邊無線趨近於0的數字;而當s = 1時,一個負數的2^-127次方是從數軸左邊無線趨近於0的數字。

    所以當E全為0的時候,實際就表示的是+-0,所以浮點數不可以在程式中出現 與0去比較(浮點數 == 0),而是要跟一段範圍去比較。

2. E全為1:

    當E全為1的時候(如果M全為0),即2的次方255 - 127 = 128,所以當S = 0時,表示1 * 2^128次方,當s = 1時表示-1*2^128次方。

    所以當E全為1時,其實表示的就是這個浮點數的取值範圍。

 

那麼我們回到上面的例題,

1. n = 9 的儲存方式是

    0000 0000 0000 0000 0000 0000 0000 1001

    float *pFloat = (float *)&n   將n強制型別轉換為float形

    系統就是認為上面的儲存方式是浮點數的儲存方式

    即1.00000000000000000001001*2^-127

    是一個及其接近0的數字,所以列印0

2. 第二種輸入方法一樣,給指標賦值9.0,指標是浮點型,

    所以系統按照浮點數的儲存方式存放這個數字,

    n為整形,系統輸出n的時候按照整形的在記憶體中的儲存方式去讀,

    所以輸出n為一個非常大的數字。

這裡在普及一下,強制型別轉換,並沒有改變什麼,只是改變了系統讀取這個二進位制數的方式。

END……