萌新不看會後悔的C++基本類型總結

在這裏插入圖片描述


       c++的基本類型包括char,short,int,long,lang lang(C++新增的),double,float,bool,其中除了double,folat兩種浮點數類型之外都有有符號和無符號兩種類型,也就是說一共12種基本類型,至於爲什麼浮點數沒有無符號類型,後面會說。

0.浮點數

浮點數包括float,和double,還有long double,這些書上面都有解釋,我們不再贅述,只挑重點講一講:

單精度float和雙精度double浮點數,那麼單精度和雙精度有什麼區別?
就是前者佔4字節,後者佔8字節,前者有效數字位數位8位,後者爲16位,還有就是取值範圍不同。
等等,這顯然不是我們想要的答案,比如說我給你舉個例子:

 float number_1 = 123456789.123456789;
 float number_2 = 123456789.123456789f;
 double number_3 = 123456789.123456789;

運行結果:
在這裏插入圖片描述
通過這個你能告訴我你就理解單精度和雙精度了嗎?我相信很多人還是隻知道有單精度和雙精度這個叫法,卻不知道具體意義。

想要知道具體,我們需要查閱 IEEE754標準,該標準定義了float和double,float有32位,double有64位,不管是32位還是64位,它們都由符號位,指數位,和尾數位構成:

種類 符號位 指數位 尾數位
float 第31位(佔1bit) 第30~23位(佔8bit) 第20~0位(佔23bit)
double 第63位(佔1bit) 第62~52位(佔11bit) 第51~0位(佔52bit)

取值範圍看指數部分,float指數部分佔8位,也就是0 ~ 255,由於有正負,所以爲-128 ~ 127, 標準規定float偏移量爲127,也就是-1-127~255-127爲-128到128。

取值範圍有-2 ^128到2 ^128,是不是夠大?也就是約等於你們熟悉的-3.4E38到+3.4E38。

精度範圍看尾數部分,23位所能表示最大的數是2 ^23-1=8388607,也就是說尾數值超過這個值後float將無法精確表示,所以float最多能表示小於8388607的小數點後8位,但絕對能保證爲7位,這也是float精度位7 ~ 8位的原因。

同理,double類型的指數位爲11位,取值範圍有-2 ^10232到2 ^10232,既爲你們熟悉的-1.7E+308~1.7E+308。
精度範圍爲2^52-1=4503599627370495,爲16位。所以精度最高位16位,一定可以保證15位,這也double精度位15 ~ 16位的原因。

也是單精度8和雙精度16的由來。

1.各種類型佔用內存大小問題

下面先來看一段代碼。
 

 char c = 'a';
 short s = 1;
 int i = 1;
 long l = 1;
 long long ll = 1;
 double d = 1.0;
 float f = 2.5f;
 bool b = 0;
// 在你的機器上面佔用多少字節,具體可以使用sizeof運算符得到:
 std::cout << sizeof(c);
 std::cout << sizeof(s);
 std::cout << sizeof(i);
 std::cout << sizeof(l);
 std::cout << sizeof(ll);
 std::cout << sizeof(d);
 std::cout << sizeof(f);
 std::cout << sizeof(b);
 //運行結果爲1,2,4,4,8,8,4,1

與所有人一樣,一上來我們先了解各個類型佔據內存的大小。

這裏有一個誤區:在不同的編譯器,每個類型佔用的內存可能是不同的,這和編譯器有關,一個類型佔用多少字節由編譯器在編譯期間決定,並不和系統是否是32位和64位有關,不要以爲在16位機器上就是16位,在36位機器上就是32位。

可以查看<limits.h> 頭文件,int和其他類型的大小是由<limits.h> 中的宏定義來決定的:

INT_MAX
//隨便寫一個定義的常量,鼠標右擊轉到聲明可以跳到limits.h頭文件查看,如下:

在這裏插入圖片描述
所以我這裏就不再列出爛大街的最大值,最小值。
我只是告訴你,這個值應該怎麼得到。要知其然,還要知其所以然。
比如我們知道char的字節爲1,一字節8位可以有256種組合,所以int的字節爲4也就是256*256等於65536,這種東西我們理解就好了,沒必要背這個最大值,最小值,只需要如何得到就好了。


2.sizeof和strlen的區別

然後說一下sizeof和strlen的區別,可能有很多萌新記不住這兩個的區別:

sizeof() 是運算符,它不是函數,不要因爲它長的像函數,就上它的當,sizeof其值在編譯時就已經計算好了,參數可以是數>組,指針,對象,函數等等,它的功能就是獲取數組,指針等類型的字節大小。
數組——編譯時分配的數組空間大小
指針——存儲該指針所用的空間大小
類型——該類型所佔空間大小
對象——對象的實際所佔空間大小
函數——函數的返回類型所佔的空間大小,這裏的返回類型自然也不能void

strlen()是函數,要運行時才能計算,參數必須字符型指針(char*),函數原型爲:
Check_return size_t __cdecl strlen(In_z const char * _Str);
該函數的功能是返回字符串的長度,該字符串可能是自己定義的,也可能是內存中隨機存儲的,該函數實際完成的功能是從代>表該字符串的第一個地址開始遍歷,知道遇到結束符NULL,返回的長度不包括NULL。

 char * ch = "nihao";
 std::cout << strlen(ch);
 // 結果爲5

3.整形字面值

與C相同,C++也有三種不同的書寫方式來書寫整數。
1.使用前一位或者兩位來標識數字常量的基數,如果第一位是1 ~ 9則表示基數爲10,也是十進制寫法。
2.如果第一位是0,第二位是1 ~ 7,則基數爲8,也就是八進制。
3.如果前兩位爲0x或者0X則表示基數爲16,相當於十六進制。

 int number_1 = 66;
 int number_2 = 066;
 int number_3 = 0x66;
 std::cout << number_1 << std::endl;
 std::cout << number_2 << std::endl;
 std::cout << number_3 << std::endl;

運行結果:
在這裏插入圖片描述
爲什麼要有這幾種書寫方式呢,在有些地方是使用八進制或者是十六進制表示,我們可以直接使用該表示方法賦值給number,而不必轉換爲十進制,總而言之,就是爲了方便,爲了偷懶,反過來,輸入識別進制是有了,反過來,C++也提供了不同進制的輸出方式,但C++默認是十進制的輸出方式,想要改變默認的十進制輸出方式,需要用到cout的一些特殊特性,頭文件iostream提供了dec,hex,oct,分別用於表示十進制,十六進制和八進制:

 int number_1 = 66;
 int number_2 = 066;
 int number_3 = 0x66;
 std::cout << std::dec;
 std::cout << number_1 << std::endl;
 std::cout << std::oct;
 std::cout << number_2 << std::endl;
 std::cout << std::hex;
 std::cout << number_3 << std::endl;

運行結果:
在這裏插入圖片描述

需要注意的是在修改之前,之前修改的格式會一直生效。


4.有無符號類型之間運算情況

       說完sizeof和strlen,繼續說基本類型的長度,計算機內存的基本單位是位(bit),8位爲一個字節,每一位有0和1兩種組合,也就是說一個字節有 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 = 256 種組合。上面使用sizeof得到char的字節爲2字節,也就是說,char類型可以表示 0~ 255 或者 -128 ~ 127 ,上面說過,除了浮點數沒有有無符合之分,剩下的類型都有有符合和無符號之分,也就是char支持0~255,也可以支持-128 ~ 127,至於我們需要有符合還是無符號的,決定於我們的應用場景。

執行運算時,如果一個運算數是有符號的,而另一個是無符號的,那麼C/C++會隱式的將有符號參數強制轉換爲無符號類型,並假設這兩個數都是非負數。
當兩種類型進行混合運算時,運算結果爲正數時,結果不會出現異常,當運算結果爲負數時就會出現異常結果,而且異常的結果往往很大。

 unsigned int usa_1 = 10;
 int sa_1 = -100;
 unsigned int usa_2 = 10;
 int sa_2 = -5;
 std::cout <<usa_1+sa_1;
 std::cout << usa_2 + sa_2;

運行結果:
在這裏插入圖片描述


5.有無符號類型之間的轉換

      下面再往深走一點,我們來說說有符合數和無符號數類型之間的轉換,也就是二進制01之間的轉換,說之前,我們需要先複習一下原碼,反碼和補碼:
原碼:
原碼就是在最高位符號位用於表示符號,其他位表示值,比如8位一字節:

正1的原碼爲00000001

負1的原碼爲10000001

反碼:
反碼的表示方法爲正數的反碼時其本身,而負數的反碼是在其原碼的基礎上,符號位不變,其餘各數取反:

正1的反碼爲00000001

負1的反碼爲11111110

補碼:
補碼的表示方法爲正數的補碼就是其本身,而負數的補碼就是在其原碼的基礎上,符號位不變,其餘各位取反,最後+1,也就是在反碼的基礎上+1:

正1的補碼000000001

負1的補碼111111111

複習了原碼反碼補碼後,我們說:

1.無符號數,不存在正負之分,所有位都用來表示數的本身。
2.有符號數,最高爲用來表示數的正負,最高位爲1則表示負數,爲0則表示爲正數。

無符號數想要轉換爲有符號數需要三步:
1.看無符號數的最高爲是否爲1。
2.如果不爲1,則有符號數就直接等於無符號數。
3.如果無符號數的最高位爲1,則將無符號數取補碼,得到的數就是有符號數。

舉個例子:

無符號數10轉換爲有符號數
無符號數10的二進制寫法:0000 1010
根據三步法得到:
有符號數10的二進制寫法:0000 1010
還是10

無符號數129轉換爲有符號數
無符號數129的二進制寫法:1000 0001
根據三步法得到:
反碼:1111 1110
補碼:1111 1111
也就是說轉換成有符號後,代表的是-127

同樣,有符號數想要轉換爲無符號數,同樣需要這三步:
1.看有符號數的最高位是否爲1,
2.如果不爲1(爲0),則無符號數就直接等於有符號數;
3.如果有符號數的最高位爲1,則將有符號數取補碼,得到的數就是無符號數。

舉個例子:

有符號數-7轉換爲無符號數
有符號數-7的二進制寫法:1000 0111
根據三步法得:
反碼:1111 1000
補碼:1111 1001
也就是無符號數249
在這裏插入圖片描述
總而言之就是看符號位,如果是1,就把它當作負數來處理反碼,補碼。


6.爲什麼會出現結果數值異常大

還記得上面有一句話是這樣說的當運算結果爲負數時就會出現異常結果,而且異常的結果往往很大。現在,我們來處理這個問題:
我們可以把變量的取值範圍當作是汽車的里程錶,一來爲了好理解,而來確實是這樣的,拿char來說:
在這裏插入圖片描述
這也就解釋了爲什麼unsigned int usa_1 = 10 和 int sa_1 = -100相加會得到那麼大的一個數,也就是常說的最大值加1變爲0的故事。

7.爲什麼浮點數沒有分有無符號類型

有無符號類型說完,我們來說說文章開頭留下的問題,爲什麼浮點數沒有有無符號之分:
想要使用unsigned,就意味着最高爲要用來表示數據,而不是正負,而浮點數定義中規定內存中的數據的第一位必須是符號位,因此兩者是矛盾的,至於在哪看定義,請點擊下面鏈接自行查看:
浮點數的定義

還有就是在某些編譯器下,會將定義的unsigned folat 和unsigned double自動轉換爲unsigned int類型,而不報錯,這時使用sizeof來測量的話得出來的是int的大小,也就是4.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章