C/C++中整數與浮點數在內存中的表示方式

  在C/C++中數字類型主要有整數與浮點數兩種類型,在32位機器中整型佔4字節,浮點數分爲float,double兩種類型,其中float佔4字節,而double佔8字節。下面來講明它們在內存中的具體表現形式:程序員

  整型:編碼

  整型變量佔4字節,在計算機中都是用二進制表示,整型有無符號和有符號兩種形式。spa

  無符號變量在定義時只須要在相應類型名前加上unsigned 無符號整型變量用32位的二進制數字表示,在與十進制進行轉化時只須要知道計算規則便可輕鬆轉化。須要注意的是在計算機中通常使用主機字節序,即採用「高高低低的方式」,數字高位在高地址位,低位在低地址位,例如咱們有一個整數0x10203040那麼它在內存中存儲的格式爲:04 03 02 01。翻譯

  有符號數將最高位表示爲符號位,0爲正數,1爲負數其他位都表示具體的數值,對於負數採用的是補碼的方式,補碼的規則是用0x100000000減去這個數的絕對值,也能夠簡單的幾位將這個數的絕對值取反加1,這樣作是爲了方便將減法轉化爲加法,在數學中兩個互爲相反數的和爲0,好比如今有一個負數數x,那麼這個x + |x| = 0這個x的絕對值是一個正數,可是用二級製表示的兩個數相加不會等於0,而計算機對於溢出採用的是簡單的將溢出位丟棄,因此令x + |x| = 0x100000000,這個最高位1,已經溢出,因此這個結果用四字節保存結果確定會是0,因此最終獲得的x = 0x100000000 - |x|。code

  浮點數:blog

  早期的小數表示採用的固定小數點的方式,好比規定在32位二級制數字當中,哪幾位表示整數部分,其他的表示小數部分,這樣表示的數據範圍有限,後來採用的是小數點浮動變化的表示方式,也就是所謂的浮點數。內存

  浮點數採用的是IEEE的表示方式,最高位表示符號位,在剩餘的31位中,從左往右8位表示的是科學計數法的指數部分,其他的表示整數部分。例如咱們將12.25f化爲浮點數的表示方式:編譯器

  首先將它化爲二進制表示1100.01,利用科學計數法能夠表述爲:1.10001 * 2^3數學

  分解出各個部分:指數部分3 + 127= 011 + 01111十一、尾數數部分:10001編譯

  須要注意的是:由於用科學計數法來表示的話,最高位確定爲1因此這個1不會被表示出來

         指數部分也有正負之分,最高位爲1表示正指數,爲0表示負指數,因此算出來指數部分後須要加上127進行轉化。

  將這個轉化爲對應的32位二級制,尾數部分從31位開始填寫,不足部分補0即:0 | 10000010 | 10001 |000000000000000000,隔開的位置分別爲符號位、指數位,尾數位。

  由於有的浮點數沒有辦法徹底化爲二進制數,會產生一個無限值,編譯器會捨棄一部份內容,也就說只能表示一個近似的數,因此在比較浮點數是否爲0的時候不要用==而應該用近似表示,容許必定的偏差,好比下面的代碼:

float fTemp = 0.0001f
if(fFloat >= -fTemp && fFloat <= fTemp)
{
    //這個是比較fFloat爲0         
}

double類型的浮點數的編碼方式與float相同,只是位數不一樣。double用11位表示指數部分,其他的表示尾數部分。

  浮點數的計算在CPU中有專門的浮點數寄存器,和對應的計算指令,在效率上比整型數據的低。

在寫程序的時候,咱們利用變量名來進行變量的識別,可是計算機根本不認識這些變量名,計算機中採用的是直接使用地址的方式找到對應的變量,同時爲了能準確找到對應的變量,編譯器會生成一個結構專門用於保存變量的標識名與對應的地址,這個標識名不是咱們定義的變量名,而是在此基礎上添加了一些符號,以下面的例子:

extern int nTemp;
int main()
{
    cout<<nTemp<<endl;
}

咱們申明一個變量,而後在不定義它的狀況下,直接使用,這個時候編譯器會報錯,表示找不到這個變量,報錯的截圖以下:

咱們能夠看到編譯器爲這個變量準備的名稱並非咱們所定義的nTemp,而是添加了其餘標示。

在聲明變量的時候編譯器會爲它準備一個標示名稱,在定義時會給它一個對應的內存地址,之後在訪問這個標示的時候編譯器直接去它對應的內存位置去尋找它,下面咱們添加這個變量的定義代碼:

 

extern int nTemp;
int nTemp = 0;
int main()
{
    cout<<nTemp<<endl;
    return 0;
}

咱們查看對應的彙編代碼:

11:       ;int nTemp = 0;
00401798   mov         dword ptr [ebp-4],0
12:       ;cout<<nTemp<<endl;

咱們能夠看到在爲這個變量初始化的時候編譯器是直接找到對應的地址[ebp - 4],沒有出現相關的變量名,因此說咱們定義的變量名只是爲了程序員可以識別,而計算機是直接採用寄存器尋址的方式來取用變量。

在編譯器中同時也看不到與變量類型相關的代碼,編譯器在使用變量是隻關心它的位置,存儲的值,以及如何將其中的二進制翻譯爲對應的內容,代碼以下:

int main()
{
    int nTemp = 0x00010101;
    float *pFloat = (float*)&nTemp;
    char *pChar = (char*)&nTemp;
    cout<<nTemp<<endl;
    cout<<*pFloat<<endl;
    cout<<pChar<<endl;
    return 0;
}

結果以下:

從這能夠看出同一塊內存由於編譯器根據類型將它翻譯爲不一樣的內容,所展示的內容不一樣。

相關文章
相關標籤/搜索