數據在內存中的存儲

關於數據在內存中的存儲這一方面,之前沒有系統的瞭解過。不過之後的學習,我有了深刻的認識。
首先,先了解以下現有的數據類型吧。

一.數據類型

1.整形
char

  • (unsigned char / signed char)

short

  • (unsigned short [int] / signed short [int] )

int

  • (unsigned int / signed int)

long

  • (unsigned long [int] / signed long [int])

2.浮點數
float
double
3.構造類型
數組類型
結構體類型 — >> struct
枚舉類型 — >> enum
聯合類型 — >> union
4.指針類型

  • void () 表示空類型,通常應用於函數的返回值類型,函數的參數,指針類型。

二.整形在內存中的存儲

1.原碼、反碼、補碼

  • 計算機中的符號數有三種表示方法,即原碼、反碼、補碼。三種表示方法均有符號位和數值位兩部分,符號位都是用0表示“正”,用1表示“負”。
  • 原碼:直接將二進制按照正負數的形式翻譯成二進制就可以。
  • 反碼:將原碼的符號位不變,其他位按位取反就行。
  • 補碼:反碼 + 1就是補碼。

2.大小端
對於整形來說,最爲重要的問題就回歸到大小端問題上。
數據 <-------由高到低
內存 -------->由低到高

  • 大端模式:數據的低位保存在內存的高地址中,而數據的高位,保存在內存的低地址中。
  • 小段模式:數據的低位保存在內存的低地址中,而數據的高位,保存在內存的高地址中。

3.判斷一個機器是大端還是小端的方法

#include<iostream>

int check_sys()
{
	int i = 1;
	return (*(char*)&i);
}
int main()
{
	int ret = check_sys();
	if(ret == 1)
		std::cout << "小端" << std::endl;
	else
		std::cout << "大端" << std::endl;
}

4.整型提升

概念:
在K&R和C89的早期實現中,基於short和char的算術運算陷入兩難的困境,因爲可能會產生兩種不同的結果。因此,在C99中很明確地定義了整型提升的規則.如果int能夠表示原始類型中的所有數值,那麼這個數值就被轉成int型,否則,它被轉成unsigned int型。這種規則被稱爲整型提升。所有其它類型都不會被整型提升改變。

char a = '2';
char b = '4';
char c = a + b;
printf("%c\n",c);

在上述過程中,儘管兩個運算符”+”和”=”的操作數全爲char型,但在中間計算過程中存在着整數提升:對於表達式a+b ,a、b都是char型,因此被提升至int型後,執行“+”運算,計算結果(int型)再賦值給c(char型),又執行了隱式的類型轉換。

是不是覺得很不可思議。
其實可以通過一種方式來驗證它:
printf(“%d”, sizeof(a + b));
大家猜猜輸出的值是多少?1,對嗎?很遺憾,不是1,大小是4
這是爲什麼呢,顯然a+b進行了整型提升,而沒有來得及將int型的值賦值給c(char型),所以大小就成了4。

3.浮點數在內存中的存儲

首先先來看下面這一串代碼

int main()
{
		int n = 9;
		float * pfloat = (float*)&n;
		printf("n的值爲:%d\n", n); 			//9
		printf("n的值爲:%f\n", *pfloat);     // 0.000000
		
		*pfloat = 9.0;   					//1091567616
		printf("num的值爲:%d\n", n);   		//9.000000
		printf("*pfloat的值爲:%f\n", *pfloat);
}

爲什麼對於內存中同一個數來說,浮點數和整數的解讀結果會差別這麼大?
原因在於浮點數的表示規則。
浮點數規則:

  • (-1)^ S *M * 2 ^ E
  • (-1)^ S表示符號位,當s = 0,v爲正數;當s = 1時,v爲負數
  • M表示有效數字,大於等於1,小於2。
  • 2^E表示指數位

舉例來說:

  1. 十進制的5.0,寫成二進制是 101.0 ,相當於 1.01×2^ 2 。 那麼,按照上面V的格式,可以得出s=0, M=1.01,E=2。
  2. 十進制的-5.0,寫成二進制是 -101.0 ,相當於 -1.01×2^2 。那麼,s=1,M=1.01,E=2

IEEE 754規定:

  1. 對於32位的浮點數,最高的一位是符號位s,接着的8位是指數E,剩下的23位爲有效數字M。
  2. 對於64位的浮點數。最高的一位是符號位s,接着的11位是指數E,剩下的52位爲有效數字M。
  3. 特別規定:關於M的表示方法:IEEE 754規定,在計算機內部保存M時,默認這個數的第一位總是1,因此可以被捨去,只保存後面的xxxxxx部 分。比如保存1.01的時候,只保存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節省1位有效 數字。以32位浮點數爲例,留給M只有23位,將第一位的1捨去以後,等於可以保存24位有效數字。
  4. 至於指數E,情況就比較複雜。 首先,E爲一個無符號整數(unsigned int) 這意味着,如果E爲8位,它的取值範圍爲0~255;如果E爲11位, 它 的取值範圍爲0~2047。但是,我們知道,科學計數法 中的E是可以出現負數的,所以IEEE 754規定,存入內存 時E 的真實值必須再加上一個中間數,對於8位的E, 這個中間數是127;對於11位的E,這個中間數是1023。 比如, 2^10的E是10,所以保存成32位浮點數時,必須 保存成10+127=137,即10001001

再看例題的第二部分。 請問浮點數9.0,如何用二進制表示?還原成十進制又是多少? 首先,浮點數9.0等於二進制的1001.0,即1.001×2^3。 //9.0 -> 1001.0 ->(-1)01.00123 -> s=0, M=1.001,E=3+127=130 那麼,第一位的符號位s=0,有效數字M等於001後面再加20個0,湊滿23位,指數E等於3+127=130,即 10000010。 所以,寫成二進制形式,應該是s+E+M,即
0 10000010 001 0000 0000 0000 0000 0000
這個32位的二進制數,還原成十進制,正是1091567616。

面試題:

1.爲什麼對於整形來說,數據存放內存中其實存放的是補碼?
答:1、使用補碼,可以將符號位和其它位統一處理。
2、減法也可按加法來處理。另外,兩個用補碼錶示的數相加時,如果最高位(符號位)有進位,則進位被捨棄。
3、補碼與原碼相互轉換,其運算過程是相同的, 不需要額外的硬件電路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章