計(jì)算機(jī)程序基礎(chǔ)教程(06):C語(yǔ)言 - 基礎(chǔ)數(shù)據(jù)類型
【基礎(chǔ)數(shù)據(jù)類型】
C語(yǔ)言將基礎(chǔ)數(shù)據(jù)分為多種類型,使用不同的關(guān)鍵詞表示,可以分為以下幾大類:整數(shù)型、浮點(diǎn)型、字符型、布爾型。
?● 整數(shù)型
整數(shù)類型又分為多種長(zhǎng)度,每種長(zhǎng)度又分為有符號(hào)數(shù)和無(wú)符號(hào)數(shù),定義關(guān)鍵詞如下:
unsigned char,無(wú)符號(hào)數(shù),長(zhǎng)度1字節(jié),表示范圍0-255。
unsigned short,無(wú)符號(hào)數(shù),長(zhǎng)度2字節(jié),表示范圍0-65535。
unsigned int,無(wú)符號(hào)數(shù),長(zhǎng)度4字節(jié),表示范圍0-4294967295。
unsigned long long,無(wú)符號(hào)數(shù),長(zhǎng)度8字節(jié),表示范圍0-18446744073709551615。
signed char,有符號(hào)數(shù),長(zhǎng)度1字節(jié),表示范圍 -127 - 128。
signed short,有符號(hào)數(shù),長(zhǎng)度2字節(jié),表示范圍 -32768 - 32767。
signed int,有符號(hào)數(shù),長(zhǎng)度4字節(jié),表示范圍 -2147483648 - 2147483647。
signed long long,有符號(hào)數(shù),長(zhǎng)度8字節(jié),表示范圍 -9223372036854775808 - 9223372036854775807。
?● 浮點(diǎn)型
float,單精度浮點(diǎn)型,長(zhǎng)度4字節(jié)。
double,雙精度浮點(diǎn)型,長(zhǎng)度8字節(jié)。
?● 字符型
字符型其實(shí)就是char數(shù)據(jù),用于存儲(chǔ)字符編碼的char數(shù)據(jù)稱為字符型數(shù)據(jù),為char類型數(shù)據(jù)賦值時(shí)可以使用一個(gè)英文字符賦值,編譯器會(huì)轉(zhuǎn)換為此字符的字符編碼。
ASCII字符集如下:
?● 布爾型
布爾型也是一個(gè)char數(shù)據(jù),但是它只用來(lái)存儲(chǔ)0和1,用于表示兩種邏輯運(yùn)算的結(jié)果,1表示對(duì)(true),0時(shí)表示錯(cuò)(false)。
在VC編譯器中使用bool定義,使用true、false賦值,示例:bool a = true;
在GCC編譯器中使用_Bool定義,使用0和1賦值,示例:_Bool a = 1;
若將布爾數(shù)據(jù)賦值為大于1的數(shù)據(jù),則統(tǒng)一表示對(duì)(true),將其當(dāng)做1處理。
?● 常量與變量
變量是可以修改的數(shù)據(jù),常量是不能修改的數(shù)據(jù),常量需要在定義時(shí)賦值,并且之后不能再修改它的值,定義數(shù)據(jù)時(shí)默認(rèn)是變量,添加const關(guān)鍵詞指定為常量。
【運(yùn)算符】
?● 數(shù)學(xué)運(yùn)算符
+,加法
-,減法
*,乘法
/,除法
%,取余
++,自加1
--,自減1
C語(yǔ)言除法運(yùn)算不保留余數(shù),對(duì)于計(jì)算結(jié)果為小數(shù)的情況需要進(jìn)行取整操作,C語(yǔ)言使用向0取整的規(guī)則,3.5取整為3,-3.5取整為-3,除法結(jié)果直接丟棄余數(shù)即為向0取整的結(jié)果。
?● 數(shù)學(xué)關(guān)系運(yùn)算符
用于判斷數(shù)據(jù)之間的大于、小于、等于關(guān)系,運(yùn)算結(jié)果為一個(gè)布爾值,關(guān)系正確返回1,錯(cuò)誤返回0。
>,大于
<,小于
==,等于
!=,不等于
>=,大于或者等于
<=,小于或者等于
?● 邏輯關(guān)系運(yùn)算符
用于對(duì)布爾數(shù)據(jù)進(jìn)行運(yùn)算,運(yùn)算結(jié)果是一個(gè)布爾值。
&&,與運(yùn)算,兩個(gè)布爾數(shù)據(jù)都為1則結(jié)果為1,否則為0。
||,或運(yùn)算,兩個(gè)布爾數(shù)據(jù)有一個(gè)為1則結(jié)果為1,否則為0。
!,非運(yùn)算,將一個(gè)布爾數(shù)據(jù)取反值,1變0,0變1。
?● 移位運(yùn)算符
將一個(gè)數(shù)據(jù)進(jìn)行算數(shù)移位操作。
<<,算數(shù)左移
>>,算數(shù)右移
使用算數(shù)右移代替除以2的操作應(yīng)該慎用,當(dāng)除法運(yùn)算無(wú)法整除時(shí)會(huì)涉及到向0取整操作,而使用算數(shù)右移會(huì)直接丟棄低位,導(dǎo)致右移結(jié)果與除法結(jié)果可能會(huì)不同。
?● 按位邏輯運(yùn)算符
將一個(gè)數(shù)據(jù)按照二進(jìn)制位進(jìn)行邏輯運(yùn)算,得出一個(gè)新的數(shù)據(jù)。
&,按位與運(yùn)算
|,按位或運(yùn)算
^,按位異或運(yùn)算,判斷兩個(gè)數(shù)字是否不同,若不同則運(yùn)算結(jié)果此位為1,否則為0。
~,按位取反運(yùn)算,將一個(gè)數(shù)據(jù)的每個(gè)二進(jìn)制位取反值得出運(yùn)算結(jié)果。
?● 賦值運(yùn)算符
=,賦值
+=,加法運(yùn)算并賦值,A += B,等同于 A = A+B
-=,減法運(yùn)算并賦值
*=,乘法運(yùn)算并賦值
/=,除法運(yùn)算并賦值
%=,取余運(yùn)算并賦值
<<=,左移運(yùn)算并賦值
>>=,右移運(yùn)算并賦值
&=,按位與運(yùn)算并賦值
|=,按位或運(yùn)算并賦值
^=,按位異或運(yùn)算并賦值
【數(shù)學(xué)運(yùn)算優(yōu)化】
當(dāng)進(jìn)行數(shù)學(xué)運(yùn)算時(shí),編譯器在特定情況下會(huì)進(jìn)行優(yōu)化,比如兩個(gè)常量之間的運(yùn)算,編譯器會(huì)在編譯期間計(jì)算出結(jié)果,無(wú)需在程序執(zhí)行期間計(jì)算,若變量與常量之間進(jìn)行乘法、除法運(yùn)算,編譯器會(huì)使用執(zhí)行速度更快的指令代替乘法或除法,得出相同結(jié)果。
其中除法指令最為耗時(shí),優(yōu)化也最為復(fù)雜,若除數(shù)為2的乘方,則轉(zhuǎn)換為右移,之后進(jìn)行向0取整規(guī)則調(diào)整,若除數(shù)不是2的乘方,則編譯器轉(zhuǎn)換為乘法,轉(zhuǎn)換原理與減法轉(zhuǎn)加法類似,也是先擴(kuò)大再縮小,這里的縮小使用移位的方式實(shí)現(xiàn)。
使用10進(jìn)制說(shuō)明轉(zhuǎn)換原理:
115 / 5 = 23
可以轉(zhuǎn)換為
115 * 2 = 230,230右移1次等于23
因?yàn)槌?與乘以2的結(jié)果相差10倍,所以除以5轉(zhuǎn)換為乘以2之后只需要再除以10即可,而除以10可以無(wú)需計(jì)算,右移1次即可。
?● 有符號(hào)變量除以9
編譯器會(huì)將除法轉(zhuǎn)換為如下指令:
除法結(jié)果無(wú)法整除時(shí)需要進(jìn)行向0取整,上述運(yùn)算后,若被除數(shù)為負(fù)數(shù),則計(jì)算結(jié)果需要額外加1才能滿足向0取整的規(guī)則,末尾的兩條指令用于實(shí)現(xiàn)加1運(yùn)算。
首先將eax中的被除數(shù)算數(shù)右移31位,之后計(jì)算結(jié)果減eax,若被除數(shù)為負(fù),則減-1,等同于加1,若被除數(shù)為正,則減0。
?● 有符號(hào)變量除以7
編譯器會(huì)將除法轉(zhuǎn)換為如下指令:
上面的優(yōu)化方案中,被除數(shù)乘以一個(gè)數(shù)之后又執(zhí)行了一個(gè)加法,之后右移2次得出除法結(jié)果,原因是編譯器進(jìn)行除以7的優(yōu)化時(shí),無(wú)法計(jì)算出誤差較小、長(zhǎng)度又不超過(guò)32位的乘數(shù),所以編譯器使用將被除數(shù)縮小再右移的方式進(jìn)行優(yōu)化。
右移2位等于除以4,這里將除以7轉(zhuǎn)換為除以4,兩者若要相等的話,被除數(shù)必須首先減去自身的3/7,這樣才能保證其1/4等于原值的1/7。
而計(jì)算被除數(shù)的3/7卻又產(chǎn)生了另一個(gè)除法,實(shí)際上這個(gè)除法也會(huì)被編譯器優(yōu)化為乘法,首先 被除數(shù) × 92492493h,之后使用rdx,等于乘法結(jié)果右移32位,這個(gè)結(jié)果不算符號(hào)位的話,就是被除數(shù)的3/7。
之后被除數(shù)與rdx相加,0x92492493轉(zhuǎn)換為二進(jìn)制是一個(gè)負(fù)數(shù)的補(bǔ)碼,若被除數(shù)為負(fù),則乘法結(jié)果為正,被除數(shù)會(huì)加一個(gè)正數(shù),等于被除數(shù)減自身3/7,若被除數(shù)為正,則乘法結(jié)果為負(fù),被除數(shù)會(huì)加一個(gè)負(fù)數(shù),等于被除數(shù)減自身3/7。
最后右移2位,得出除以7的結(jié)果。
?● 無(wú)符號(hào)變量除以7
編譯器會(huì)將除法轉(zhuǎn)換為如下指令:
這里除數(shù)為7,也會(huì)有之前的問(wèn)題,就是編譯器無(wú)法計(jì)算出誤差較小、長(zhǎng)度又不超過(guò)32位的乘數(shù)。
其實(shí)第三條乘法指令之后,使用存儲(chǔ)高32位結(jié)果的edx就是除法結(jié)果,只不過(guò)這個(gè)結(jié)果有時(shí)候會(huì)不太精確,可能會(huì)比正確值大1,使用之后的4條指令進(jìn)行調(diào)整將會(huì)消除誤差。
下面解釋后4條指令的作用: