解開C語(yǔ)言的秘密《關(guān)鍵字》(第二期)
今天我們會(huì)穿插著講一些關(guān)鍵字之外的內(nèi)容:
目錄
1、數(shù)據(jù)類型
2、變量命名規(guī)則
?3、最冤枉的關(guān)鍵字sizeof
4、signed、unsigned關(guān)鍵字
5、大小端存儲(chǔ)
1、數(shù)據(jù)類型
首先我們通過(guò)一張圖來(lái)認(rèn)識(shí)一下C語(yǔ)言中的數(shù)據(jù)類型:

那么我們常用數(shù)值類型在我們內(nèi)存中占多大的空間呢?這里我們可以用一個(gè)關(guān)鍵字sizeof求一下所占空間大??!(sizeof下面會(huì)講)

如上圖可知,可能有小伙伴會(huì)有疑問,為什么long跟int占的空間一樣大呢?(嚴(yán)格意義應(yīng)該用 zu% 打印sizeof返回的值,因?yàn)閟izeof 定義是 size_t 可以理解成無(wú)符號(hào)整型)
其實(shí)是這樣的,long可以有多種定義,可以是32位,也可以是64位,C++標(biāo)準(zhǔn)上只是說(shuō)long至少要和int一樣大,也就是long只要>=int就可以了。
那么我們接著來(lái)思考,那么C語(yǔ)言中為什么要有類型呢?
本質(zhì)對(duì)內(nèi)存進(jìn)行劃分,按需索?。?/p>
C語(yǔ)言中為什么會(huì)存在這么多的類型呢?
應(yīng)用場(chǎng)景不同,解決應(yīng)用場(chǎng)景對(duì)應(yīng)的計(jì)算方式不同,需要空間的大小也是不同的,本質(zhì):用最小成本解決各種多樣化的場(chǎng)景問題!
2、變量命名規(guī)則
不知道小伙伴們?cè)陂喿x其他人代碼的時(shí)候會(huì)不會(huì)出現(xiàn) int xishu; int hanshu; 這樣的例子,看著真是讓人頭痛,其實(shí)良好的命名規(guī)則和代碼風(fēng)格在以后面試中會(huì)留下好印象的,所以,養(yǎng)成良好的命名規(guī)范從現(xiàn)在做起!?
規(guī)則一:命名應(yīng)該直觀并且可以拼讀,可見名知意,不允許使用拼音!英文不能復(fù)雜,用詞應(yīng)當(dāng)準(zhǔn)確。
規(guī)則二:命名長(zhǎng)度應(yīng)該適中(最短長(zhǎng)度,最大信息),C語(yǔ)言是一種簡(jiǎn)捷的語(yǔ)言,命名也應(yīng)如此,比如變量名MaxVal就比MaxValueUntilOverflow要好很多。標(biāo)識(shí)符長(zhǎng)度一般不要太長(zhǎng),英文詞盡量不要縮寫。
規(guī)則三:當(dāng)標(biāo)識(shí)符由多個(gè)詞組成的時(shí)候,每個(gè)詞的第一個(gè)字母大寫,其他全部小寫,例如:QuickSort(快速排序),這樣的名會(huì)更清晰,比拼英或者單個(gè)字母好多了,這個(gè)叫做大駝峰命名。(建議函數(shù)這樣命名)
規(guī)則四:盡量避免名字中出現(xiàn)數(shù)字編號(hào),如Value1、Value2等,除非邏輯上需要編號(hào),初學(xué)者總是喜歡用代編號(hào)的變量名或函數(shù)名,這樣子看上去簡(jiǎn)單方便,但這樣的命名無(wú)疑是一顆定時(shí)炸彈,一定要改過(guò)來(lái)!
規(guī)則五:程序中不得出現(xiàn)僅靠大小寫區(qū)分的相似的標(biāo)識(shí)符,例如:int x = 0; int X = 0;
規(guī)則六:一個(gè)函數(shù)名禁止被用于其他支出,例如:我們有一個(gè)fun函數(shù),變量就不能以fun命名!不要讓變量名和函數(shù)名一樣!
規(guī)則七:所有宏定義,枚舉常量,只讀變量全用大寫字母命名,用下劃線分隔單詞,比如:#define INT_MAX 100;
規(guī)則八:定義變量的同時(shí)不要忘記初始化。定義變量時(shí)編譯器并不一定清空了這塊內(nèi)存,它的值可能是隨機(jī)值。
我們目前暫時(shí)只需要:見名知意,大小駝峰,數(shù)字字母下劃線即可。
?3、最冤枉的關(guān)鍵字sizeof
我們先了解下sizeof的幾種寫法:

這里我們可以看到,前面三種寫法都是正確的,但是為什么第四種寫法就會(huì)報(bào)錯(cuò)呢?
首先,從第三個(gè)printf可以看出來(lái)sizeof可以不帶括號(hào),可以證明sizeof并不是函數(shù)!而是關(guān)鍵字或者操作符,而且函數(shù)調(diào)用會(huì)壓棧,sizeof并不會(huì)壓棧,再者sizeof是一個(gè)關(guān)鍵字,int也是一個(gè)關(guān)鍵字,sizeof是不能直接去求另一個(gè)特定關(guān)鍵字的大??!
sizeof常用的場(chǎng)景我們后期碰到會(huì)講解的,比如求數(shù)組元素個(gè)數(shù): sizoef(arr) / sizeof(arr[0]);
4、signed、unsigned關(guān)鍵字
我們之前講過(guò)一個(gè)變量的創(chuàng)建是要在內(nèi)存中開辟空間的,空間的大小是根據(jù)不同的類型而決定的。 那么,數(shù)據(jù)在所開辟內(nèi)存中到底是如何存儲(chǔ)的呢?
我們先來(lái)了解概念,數(shù)據(jù)的存儲(chǔ)分為有符號(hào)數(shù)和無(wú)符號(hào)數(shù),那么計(jì)算機(jī)中有符號(hào)數(shù)有三種表示方法,分別是原碼、反碼、補(bǔ)碼。
這三種方法均有符號(hào)為和數(shù)值位兩部分,符號(hào)位都是用0表示正,用1表示負(fù),而數(shù)值位三種表示方法各不相同:
如果一個(gè)數(shù)是負(fù)數(shù),那么就要遵守下面規(guī)則進(jìn)行轉(zhuǎn)化:
原碼:直接將一個(gè)二進(jìn)制按照正負(fù)數(shù)的形式翻譯成二進(jìn)制就可以了。
反碼:將原碼的符號(hào)位不變,其他位一次按位取反。
補(bǔ)碼:反碼+1就可以得到補(bǔ)碼。
如果一個(gè)數(shù)是正數(shù),那么它的反碼原碼補(bǔ)碼都相同。
無(wú)符號(hào)數(shù):不需要轉(zhuǎn)換
對(duì)于整型來(lái)說(shuō):數(shù)據(jù)存放在內(nèi)存中是補(bǔ)碼。

上圖我們可以看到,有符號(hào)位在內(nèi)存中的存儲(chǔ)跟我們上述所說(shuō)的是一樣的,那么為什么內(nèi)存看到的是反過(guò)來(lái)的呢,因?yàn)槲覀冞@里是小端存儲(chǔ)(后面講),那么我們的無(wú)符號(hào)數(shù)是沒有符號(hào)位的,并且原碼反碼補(bǔ)碼都相等。
那么負(fù)數(shù)補(bǔ)碼如何轉(zhuǎn)換成原碼呢?
方法一:補(bǔ)碼-1然后除符號(hào)位按位取反
方法二:符號(hào)位不變按位取反然后加1
我們來(lái)看一個(gè)unsigend的例子:
定義一個(gè)變量: unsigned int b = -10;? 這個(gè)代碼有問題嗎?沒有問題?。?!
我們知道,定義一個(gè)變量運(yùn)行時(shí)就是開辟一個(gè)空間,先有空間才有內(nèi)容,我們現(xiàn)在將 -10轉(zhuǎn)化為二進(jìn)制補(bǔ)碼:1111 1111 1111 1111 1111 1111 1111 0110?在我們數(shù)據(jù)保存到空間的時(shí)候,數(shù)據(jù)已經(jīng)被轉(zhuǎn)化成二進(jìn)制了!所以整型在存儲(chǔ)的時(shí)候,空間是不關(guān)心存什么內(nèi)容,他只需要把這一串二進(jìn)制存儲(chǔ)起來(lái)就行,那么我們?unsigned int?這個(gè)變量類型在什么時(shí)候起效果呢?在我們讀取的時(shí)候起效果,也就是說(shuō),類型決定了如何解釋空間內(nèi)部保存的二進(jìn)制序列!
我們來(lái)看代碼:

第一個(gè)printf 就是在實(shí)際輸出的時(shí)候以u(píng)nsigned int 來(lái)解釋對(duì)應(yīng)的空間的
第二個(gè)printf 就是在實(shí)際輸出的時(shí)候以signed int 來(lái)解釋對(duì)應(yīng)空間的
所以我們就要來(lái)探討變量存和取的過(guò)程:
變量存:字面數(shù)據(jù)必須先轉(zhuǎn)成補(bǔ)碼,再放入空間當(dāng)中,所以,所謂符號(hào)位,完全是看數(shù)據(jù)本身是否攜帶+-號(hào),和變量是否有符號(hào)無(wú)關(guān)!
變量取:取數(shù)據(jù)一定要先看變量本身類型,然后才決定要不要看最高符號(hào)位,如果不需要,直接二進(jìn)制轉(zhuǎn)十進(jìn)制,如果需要?jiǎng)t需轉(zhuǎn)成原碼,然后才能識(shí)別(當(dāng)然符號(hào)位在哪里,我們要明確大小端)。
同過(guò)上面的講解,可能小伙伴還有一個(gè)問題,為什么計(jì)算機(jī)中要使用補(bǔ)碼呢?
在計(jì)算機(jī)系統(tǒng)中,數(shù)值一律用補(bǔ)碼來(lái)表示和存儲(chǔ)。原因在于,使用補(bǔ)碼,可以將符號(hào)位和數(shù)值域統(tǒng)一處理; 同 時(shí),加法和減法也可以統(tǒng)一處理(CPU只有加法器)。此外,補(bǔ)碼與原碼相互轉(zhuǎn)換,其運(yùn)算過(guò)程是相同的,不 需要額外的硬件電路。
5、大小端存儲(chǔ)
?要了解大小端,我們先拋出一個(gè)問題,見代碼:

為什么a變量存在內(nèi)存中是反過(guò)來(lái)的呢?這里我們就要引入大小端的概念了!
如何理解大小端呢?
我們知道內(nèi)存是連續(xù)的存儲(chǔ)空間,有高地址和低地址之分,那么我們的數(shù)據(jù)也要按照字節(jié)為單位劃分,數(shù)據(jù)是有高權(quán)值位和低權(quán)值位的區(qū)別的,比如 0xAA BB CC DD,AA的權(quán)值就大于DD的權(quán)值,那么大小端是如何存放的呢?(目前基本都是小端存儲(chǔ))
大端:按照字節(jié)為單位,低權(quán)值位數(shù)據(jù)存儲(chǔ)在高地址處,就叫做大端
小端:按照字節(jié)為單位,低權(quán)值位數(shù)據(jù)存儲(chǔ)再低地址處,就叫做小端
圖解:

所以,數(shù)據(jù)取的時(shí)候不僅僅要考慮原反補(bǔ),還要考慮大小端,如何存就如何取。
以上就是我們本期的內(nèi)容了,如果有疑問可以隨時(shí)問我哦,我們下期見!?