C语言程序设计 | 整型、浮点型在内存中的存储方式
整型在內存中的存儲
一個變量的創建要在內存中開辟空間,空間的大小是根據不同的類型決定的。
那數據在數據在所開辟的空間中是如何存儲的呢?
首先我們要了解三個概念:
原碼 反碼 補碼
計算機中的有符號數有三種表示方法,即原碼、反碼和補碼。
三種表示方法均有符號位和數值位兩部分,符號位都是用0表示正,用1表示負,而數值為的三種表示方法各不同。
原碼:
直接將二進制按照正負數的形式翻譯成二進制就可以。
反碼:
將原碼的符號位不變,其他位依次按位取反就可以得到了。
補碼:
反碼+1就可以得到補碼。
正數的原碼、反碼、補碼相同。
我們所看到的二進制是原碼的形式,而它們在內存中是以補碼的形式存放的。
下面來舉幾個例子
對于I,它的原碼是:
00000000 00000000 00000000 0001010
而它所存放在內存是補碼,而正數的補碼即是它的原碼,所以存放形式為:
00000000 00000000 00000000 0001010
對于j, 它的原碼是:
10000000 00000000 00000000 0001000
它的反碼為:
11111111 11111111 11111111 1110111
它的補碼為:
11111111 11111111 11111111 1111000
它存放在內存中就是以上面的補碼形式存放的。
為什么我們要以這種補碼的形式存放在內存中呢?
在計算機系統中,數值一律用補碼來表示和存儲。原因在于,使用補碼,可以將符號位和數值域統一處理。同時,加法和減法也可以統一處理(CPU只有加法器)此外,補碼和原碼相互轉換,其運算過程是相同的,不需要額外的硬件電路
那如何用加法器來實現減法呢?
因為負數用補碼來存放
所以例如
i = 1-1
我們可以把它看成
i = 1 + (-1)
1的補碼為
00000000 00000000 00000000 0000001
-1的補碼為
11111111 11111111 11111111 1111111
兩者相加得到
00000000 00000000 00000000 0000000
這就是我們想要的結果,同理除法和乘法也可以用加法器來實現。
下面我們要了解不同字節的數據類型之間的計算方式。
如果我們要將一個高字節的數據存放在一個低字節的類型中,例如將int型存放在char型中,我們要用到一種方法,叫做截斷
為什么是截斷?
下面舉一個例子
對于1,它在內存中存放的形式是這樣的:
而我們將它存放在僅僅只有一個字節的char型中,它就會被截斷為最低位的那個字節中的數據
即:00000001
那如果我們想要將一個低字節的數據類型用高字節的方式輸出呢?
例如:
它的輸出結果為
為什么我們會得到這樣一個奇怪的數據呢?
在這里,我們還要引入一個概念,叫做整型提升。
那么,什么是整型提升?
對于一個低字節的數據類型,如果我們將它轉換為高字節的數據類型,我們需要將它的二進制位補充到對應的字節,補充的規則是當數據為有符號數的時候,補符號數,如果為無符號數,補0.
對于上面的代碼,我們就來分析一下。
首先整型-128的原碼為
10000000 00000000 00000000 1000000
反碼
11111111 11111111 11111111 0111111
補碼
11111111 11111111 11111111 10000000
然后將其截斷,存放在char中的二進制位為
10000000
同時我們將其以無符號整型的方式輸出,所以需要先將其提升為整型,它的符號位為1,則前面全部補1
11111111 11111111 11111111 10000000
而因為我們輸出的是無符號的整形,所以我們將上面的二進制補碼直接當作原碼,所以我們就得到了這個巨大的數字。
浮點型在內存中的存儲
#include<stdio.h> int main() {int n = 1;float *p = (float *)&n;printf("n = %d\n",n);printf("*p = %f\n\n",*p);*p = 1.0;printf("n = %d\n",n);printf("*p = %f\n",*p);return 0; }對于上面這段代碼,它的運行結果是:
*明明n 和 p在內存中是同一個數,為什么浮點數和整型的解讀結果會差別這么大?要理解這個結果,一定要搞懂浮點數在計算機內部的表示方法
根據國際標準IEEE(電氣和電子工程協會)754,任意一個二進制浮點數V可以表示成下面的形式:
- (-1)^ S * M * 2 ^ E
- (-1)^ S表示符號位,當S=0,V為整數。當S=1,V為負數。
- ?M表示有效數字,大于等于1,小于2
- ?2 * E表示指數位
那如何理解呢?首先我畫個圖來大概描述一下
這個是二進制前八位代表的數值,當我們要取到小于1的數時,我們可以想到,用2的負數次方來表示,于是可以這樣表示
所以十進制的5.0,我們將其用二進制表示就是101.1,相當于(-1) ^ 0 x 1.01 x 2 ^ 2。
用上面的格式的話 S = 0,M = 1.01,E = 2。
那它在內存中又是怎么存放的呢?
IEEE 754 規定 : 對于32位的單精度浮點數,最高的1位是符號位S,接著的8位是指數E,剩下的23位為有效數字M
如下圖:
對于64位的雙精度浮點數,最高的1位是符號位S,接著的11位是指數E,剩下的52位為有效數字M
這里的圖我就不畫了,可以參考上面的自行腦補。
在之前有一條性質,M表示有效數字,大于等于1,小于2,也就是說,這個M必為1,原先的寫法為1.xxxxxxxx,而我們可以將這個1省略掉,因為它是一個固定值,我們可以直接寫為后面的xxxxxxx,這樣我們就可以節約一位,就可以表示24位的有效數字,而當我們要讀取的時候,再將這個第一位的1給加上去。
而指數E,它的規則就顯得有些復雜
E作為一個無符號的整數,這表示著如果E為8位,它的取值范圍為0-255(2^8 -1)。如果E為11位,它的取值范圍為0-2047.但是我們知道,科學計數法中的E時可以出現負數的,**所以IEEE 754規定,存入內存時E的真實值必須再加上一個中間數,**對于8位的E,這個中間數是127(2 ^ (8-1)-1) ;對于11位的E,這個中間值是1023.比如,2^10的E是1-,所以保存成32位浮點數時,必須保存成10+127=137,即10001001。
而當我們將指數E從內存中取出的時候,存在三種情況。
E不全為0或者不全為1
這時,浮點數就采用下面的規則表示,即指數E的計算值減去中間數127或1023,得到真實值,再將有效數字M前面加上第一位的1。
比如:0.5的二進制為0.1,用上述表示法則為(-1)^ 0 * 1.0 * 2 ^ (-1),階碼為-1+127 = 126.
126二進制表示為
01111110
尾數1.0去掉常值1,剩下一個0,補齊0到23位,所以二進制表示形式位:
0 01111110 00000000000000000000000
E全為0
這時,指數E等于1-127(1023)得到真實值,有效數字M不再加上第一位的1,而是還原為0.xxxxxx的效數,這樣做是為了±0及無限趨近于0的數字
E全為1
這是,如果有效數字M全為0,表示±無窮大(正負取決于符號位S)
總結
以上是生活随笔為你收集整理的C语言程序设计 | 整型、浮点型在内存中的存储方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言程序设计 | 大端小端存储解析以及
- 下一篇: 数据结构与算法 | 插值查找