1.引言
眾所周知,C語言中有幾種基本的內(nèi)置數(shù)據(jù)類型:
char - 字符數(shù)據(jù)類型
short - 短整型
int - 整型
long - 長整型
long long - 更長的整型
float - 單精度浮點(diǎn)數(shù)
double - 雙精度浮點(diǎn)數(shù)
那為什么要設(shè)置這么多內(nèi)置數(shù)據(jù)類型呢?類型的意義是什么?
本文將為大家介紹整型和浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)模式和使用方法。
2.正文
1.1類型的歸類和意義
本文主要講解整型和浮點(diǎn)數(shù),其他類型大家感興趣可以自行了解
整型家族:
signed char
unsigned char
signed short
unsigned short
signed int
unsigned int
signed long
unsigned long
其中char雖然是字符類型,但是字符類型在存儲(chǔ)的時(shí)候,其實(shí)存儲(chǔ)的是字符的ASCII碼值,ASCII碼值是整數(shù),所以char也是整型家族的。
signed表示的是有符號(hào)的類型,如:signed int a;
unsigned表示的是無符號(hào)的類型,如:unsigned int b;
有正負(fù)的數(shù)據(jù)可以存放在有符號(hào)的變量中,只有正數(shù)的數(shù)據(jù)可以存放在無符號(hào)的變量中。
浮點(diǎn)數(shù)家族:
float
double
這么多數(shù)據(jù)類型的意義到底是什么呢?
第一,數(shù)據(jù)類型決定了使用這個(gè)類型開辟內(nèi)存空間的大小,而大小又決定了使用范圍。
第二,決定了如何看待內(nèi)存空間的視角。
大家可能不太好理解這些抽象的知識(shí)點(diǎn),接下來我就給大家通過舉例子的方法詳細(xì)介紹。
1.2整型在內(nèi)存中的存儲(chǔ)
有符號(hào)數(shù)在計(jì)算機(jī)中有三種表示方法,即原碼、反碼、補(bǔ)碼。
三種方法的最高位都為符號(hào)位:0正1負(fù),其他位都是數(shù)值位。
原碼就是直接將該數(shù)據(jù)以正負(fù)的形式轉(zhuǎn)化為二進(jìn)制。
反碼就是原碼的符號(hào)位不變,其他位按位取反。
補(bǔ)碼,反碼+1就得到了補(bǔ)碼。
整型在內(nèi)存中實(shí)際存儲(chǔ)的是該數(shù)據(jù)的補(bǔ)碼的二進(jìn)制。
所以我們在存儲(chǔ)時(shí)應(yīng)該先將十進(jìn)制的數(shù)字轉(zhuǎn)換為二進(jìn)制的原碼,然后按規(guī)則存儲(chǔ),最終存儲(chǔ)的是補(bǔ)碼。
值得一提的是,正數(shù)和無符號(hào)數(shù)的原反補(bǔ)碼相同,所以只有負(fù)數(shù)需要通過原碼計(jì)算求得補(bǔ)碼。而且無符號(hào)數(shù)的最高位不是符號(hào)位,也是數(shù)據(jù)位。
例如:int a = -1;
此時(shí)我們要將-1存進(jìn)int類型的a中,首先應(yīng)該將-1轉(zhuǎn)化為二進(jìn)制,得到原碼
-1的原碼:10000000000000000000000000000001
再通過原碼求得-1的反碼和補(bǔ)碼。
-1的反碼:1111111111111111111111111111111111110
-1的補(bǔ)碼:1111111111111111111111111111111111111
補(bǔ)碼也就是這里a在內(nèi)存中實(shí)際存儲(chǔ)的數(shù)據(jù)。
1.2.1例
如果大家還是不理解,我再給大家舉一個(gè)更全面,更復(fù)雜的例子。
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a = %d, b = %d, c = %u", a, b, c);
return 0;
}
這里我先給大家擴(kuò)展幾個(gè)個(gè)知識(shí)點(diǎn):
%d是打印有符號(hào)整型,意思是打印的一定是有符號(hào)整型,從計(jì)算機(jī)的視角來看,即使不是有符號(hào)數(shù),他也會(huì)認(rèn)為是有符號(hào)數(shù)。
%u是打印無符號(hào)整型,意思是打印的一定是無符號(hào)整型,從計(jì)算機(jī)的視角來看,即使不是無符號(hào)數(shù),他也會(huì)認(rèn)為是無符號(hào)數(shù)。
如果把一個(gè)負(fù)數(shù)強(qiáng)行存儲(chǔ)在unsigned類型中,當(dāng)使用%d打印時(shí),即使符號(hào)位有正負(fù)也會(huì)被認(rèn)為是數(shù)據(jù)。
那這里的代碼結(jié)果是什么呢?a,b,c的值分別是多少呢?
運(yùn)行代碼,我們來看結(jié)果。
1.2.2解析
結(jié)果是a=-1,b=-1,但c卻是255,這是什么原因?
讓我來為大家一步一步解析。
第一步,要存儲(chǔ)-1的值,就必須先算出-1的原碼,反碼,補(bǔ)碼,最終把補(bǔ)碼存進(jìn)內(nèi)存中.
-1的原碼:10000000000000000000000000000001
-1的反碼:11111111111111111111111111111110
-1的補(bǔ)碼:11111111111111111111111111111111
此時(shí)要將這32位的數(shù)據(jù)存進(jìn)char類型的a中,但char最多能存儲(chǔ)8位的數(shù)據(jù),強(qiáng)行存儲(chǔ)就會(huì)發(fā)生截?cái)?,?shí)際a存進(jìn)去的是11111111(優(yōu)先存儲(chǔ)低地址),b和c同理。(a和b本質(zhì)是相同的,以下就拿c來講解)
第二步,這里要以%d、%d、%u的形式來分別打印a,b,c。上面給大家說過,%d和%u都是打印整型的,而這里的a,b,c都是char類型,使用的時(shí)候就要發(fā)生整型提升,整型提升的規(guī)則是,負(fù)數(shù)就補(bǔ)符號(hào)位,正數(shù)就補(bǔ)0,無符號(hào)數(shù)也補(bǔ)0。
第三步,c發(fā)生整型提升(a,b也會(huì)),c的類型是unsigned char,是無符號(hào)數(shù),所以高位補(bǔ)0。
得到整型提升后的補(bǔ)碼:00000000000000000000000011111111
第四步,c是以%u的形式打印的,也就是打印無符號(hào)數(shù),所以此時(shí)的補(bǔ)碼就等于原碼。而這里的補(bǔ)碼換算為十進(jìn)制,就是255,所以c打印出的值是255。
講到這里我相信在座的各位都已經(jīng)徹底理解了整型在內(nèi)存中是如何存儲(chǔ)的。
1.3大小端
這里再為大家補(bǔ)充一個(gè)知識(shí)點(diǎn),大小端存儲(chǔ)模式。
什么是大小端?
大端存儲(chǔ)模式:數(shù)據(jù)的高位保存在內(nèi)存的低地址處,低位保存在內(nèi)存的高地址處。
小端存儲(chǔ)模式:數(shù)據(jù)的低位保存在內(nèi)存的低地址處,高位保存在內(nèi)存的低地址處。
比如:int a = 0x11223344;在小端存儲(chǔ)模式的編譯器里,內(nèi)存中的地址為44332211,在大端存儲(chǔ)模式的編譯器里,內(nèi)存中的地址為11223344。
本人使用的是VS2019,此處通過調(diào)試來測試VS2019的存儲(chǔ)模式。
可以看出,VS2019采用的是小端存儲(chǔ)模式。
那為什么要有大小端存儲(chǔ)模式呢?
這是因?yàn)樵谟?jì)算機(jī)系統(tǒng)中,我們是以字節(jié)為單位的,每個(gè)地址單元都對應(yīng)著1個(gè)字節(jié)。
1個(gè)字節(jié)為8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器)。
另外,對于位數(shù)大于8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于1個(gè)字節(jié),那么必然存在著一個(gè)如何將多個(gè)字節(jié)安排的問題。因此就導(dǎo)致了大端存儲(chǔ)模式和小端存儲(chǔ)模式。
1.4浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)
首先我們必須要知道的是,浮點(diǎn)數(shù)和整型在內(nèi)存中的存儲(chǔ)方式是不同的。
1.4.1浮點(diǎn)數(shù)存儲(chǔ)
根據(jù)國際標(biāo)準(zhǔn)IEEE(電氣和電子工程協(xié)會(huì)) 754,任意一個(gè)二進(jìn)制浮點(diǎn)數(shù)可以表示成下面的形式:
(-1)^S × M × 2^E
其中,(-1)^S表示符號(hào)位,當(dāng)S=0時(shí),為正數(shù),當(dāng)S=1時(shí),為負(fù)數(shù)。
M表示有效數(shù)字,大于1,小于2.
2^E表示指數(shù)位。
存儲(chǔ)時(shí):
對于32位的浮點(diǎn)數(shù),最高的1位是符號(hào)位s,接著的8位是指數(shù)E,剩下的23位為有效數(shù)字M。
對于64位的浮點(diǎn)數(shù),最高的1位是符號(hào)位S,接著的11位是指數(shù)E,剩下的52位為有效數(shù)字M。
M:在計(jì)算機(jī)內(nèi)部保存M時(shí),默認(rèn)這個(gè)數(shù)的第一位總是1,因此可以被舍去,只保存后面的xxxxxx部分(1.xxxxxx)
E:首先,E是一個(gè)無符號(hào)整數(shù)。
存入內(nèi)存時(shí)E的真實(shí)值必須再加上一個(gè)中間數(shù),對于8位的E,這個(gè)中間數(shù)是127;對于11位的E,這個(gè)中間數(shù)是1023。
例如:float a = 5.5,5.5寫成二進(jìn)制就是101.1,也就是1.011×2^2,按照上面的公式可以得出,S=0,M=1.011,E=2。
E+127 = 129,129的二進(jìn)制是10000001
所以此時(shí)內(nèi)存中存儲(chǔ)的應(yīng)該是:0 10000001 01100000000000000000000
換算成16進(jìn)制就是0x40b00000,我們來測試一下,看是不是這樣的。
取出時(shí):文章來源:http://www.zghlxwxcb.cn/news/detail-421805.html
分為三種情況:
1 - E不全為0或不全為1:指數(shù)E的計(jì)算值減去127(或1023),得到真實(shí)值,再將有效數(shù)字M前加上第一位的1。也就是存儲(chǔ)時(shí)的操作反過來操作回去。
2 - E全為0:浮點(diǎn)數(shù)的指數(shù)E等于1-127(或者1-1023)即-126,即為真實(shí)值。
有效數(shù)字M不再加上第一位的1,而是還原為0.xxxxxx的小數(shù)。這樣做是為了表示±0,以及接近于0的很小的數(shù)字。
3 - E全為1:如果有效數(shù)字M全為0,表示±無窮大(正負(fù)取決于符號(hào)位S)。文章來源地址http://www.zghlxwxcb.cn/news/detail-421805.html
到了這里,關(guān)于深度剖析數(shù)據(jù)在內(nèi)存中的存儲(chǔ)——int類型(整型)和float類型(浮點(diǎn)數(shù))在內(nèi)存中是如何存儲(chǔ)和使用的?的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!