不代表全部內容
- 第二章 型別、常量及變數
- 2.1 C++的單詞
- 2.2 預定義型別(內建資料型別)及值域和常量
- 2.2.1 常見預定義型別
- 2.2.2預定義型別的數值輸出格式化
- 2.3 變數及其型別解析
- 2.3.1 變數的宣告和定義(C++11標準3.1節)
- 2.3.2 變數的初始化(C++11標準8.5節)
第二章 型別、常量及變數
2.1 C++的單詞
單詞包括常量、變數名、函式名、引數名、型別名、運算子、關鍵字等。
關鍵字也被稱為保留字,不能用作變數名。
預定義型別如int等也被當作保留字
char16_t和char32_t是C++11引入的兩種新的字元型別,用於表示特定大小的Unicode字元
例如 char16_t x = u'馬';
wchar_t表示char16_t ,或char32_t
nullptr表示空指標
需要特別注意的是:char可以顯示地宣告為帶符號的和無符號的。因此C++11標準規定char,signed char和unsigned char是三種不同的型別。
但每個具體的編譯器實現中,char會表現為signed char和unsigned char中的一種。
unsigned char ua = ~0;
printf("%d ", ua);//輸出255
signed char ub = ~0;
printf("%d ", ub);//輸出-1
char uc = ~0;
printf("%d", uc);//輸出-1
2.2 預定義型別(內建資料型別)及值域和常量
2.2.1 常見預定義型別
型別的位元組數與硬體、作業系統、編譯有關。假定VS2019採用X86編譯模式。
void:位元組數不定,常表示函式無參或無返回值。
void
是一個可以指向任意型別的指標型別。它本質上是一個“無型別”*的指標,這意味著它可以指向任何型別的資料,而不關心具體的資料型別。
int n = 0721;//前置0代表8進位制
double pi = 3.14;
void* p = &n;
cout << *(int*)p << endl;//不能直接解引用哦
p = π
cout << *(double*)p << endl;
- bool:單位元組布林型別,取值false和true。
- char:單位元組有符號字元型別,取值-128~127。
- short:兩位元組有符號整數型別,取值-32768~32767。
- int:四位元組有符號整數型別,取值-231~231-1 。
- long:四位元組有符號整數型別,取值-231~231-1 。
- float:四位元組有符號單精度浮點數型別,取值-1038~1038。
- double:八位元組有符號雙精度浮點數型別,取值-10308~10308。
注意:預設一般整數常量當作為int型別,浮點常量當作double型別。 - char、short、int、long前可加unsigned表示無符號數。
- long int等價於long;long long佔用八位元組。
- 自動型別轉換路徑(數值表示範圍從小到大):
char→unsigned char→ short→unsigned short→ int→unsigned int→long→unsigned long→float→double→long double。
數值零自動轉換為布林值false,數值非零轉換為布林值true。 - 強制型別轉換的格式為:
(型別表示式) 數值表示式 - 字元常量:‘A’,‘a’,‘9’,‘\’’(單引號),‘\’(斜線),‘\n’(換新行),‘\t’(製表符),‘\b’(退格)
- 整型常量:9,04,0xA(int); 9U,04U,0xAU(unsigned int); 9L,04L,0xAL(long); 9UL, 04UL,0xAUL(unsigned long), 9LL,04LL,0xALL(long long);
這裡整型常量的型別相信大家看後面的字母也能看出來,例如L代表long,U代表unsigned
2.2.2預定義型別的數值輸出格式化
- double常量:0.9, 3., .3, 2E10, 2.E10, .2E10, -2.5E-10
- char: %c; short, int: %d; long:%ld; 其中%開始的輸出格式符稱為佔位符。
- 輸出無符號數用u代替d(十進位制),八進位制數用o代替d,十六進位制用x代替d
- 整數表示寬度如printf(“%5c”, ‘A’)列印字元佔5格(右對齊)。%-5d表示左對齊。
- float:%f; double:%lf。float, double:%e科學計數。%g自動選寬度小的e或f。
- 可對%f或%lf設定寬度和精度及對齊方式。“%-8.2f”表示左對齊、總寬度8(包括符號位和小數部分),其中精度為2位小數。
- 字串輸出:%s。可設定寬度和對齊:printf(“%5s”,”abc”)。
- 字串常量的型別:指向只讀字元的指標即const char *, 上述”abc“的型別。
- 注意strlen(“abc”)=3,但要4個位元組儲存,最後儲存字元‘\0’,表示串結束。
2.3 變數及其型別解析
2.3.1 變數的宣告和定義(C++11標準3.1節)
- 變數說明:描述變數的型別及名稱,但沒有初始化。可以說明多次。
- 變數定義:描述變數的型別及名稱,同時進行初始化。只能定義一次。
- 說明例子:extern int x; extern int x; //變數可以說明多次
- 定義例子:int x=3; extern int y=4; int z; //全域性變數z的初始值為0
- 模組靜態變數:使用static在函式外部定義的變數,只在當前檔案(模組)可用。可透過單目::訪問。
- 區域性靜態變數:使用static在函式內部定義的變數。
static int x, y; //模組靜態變數x、y定義,預設初始值均為0
int main( ){
static int y; //區域性靜態變數y定義, 初始值y=0
return ::y+x+y;//分別訪問模組靜態變數y,模組靜態變數x,區域性靜態變數
}
為了允許把程式拆分成多個邏輯部分來編寫,C++支援分離式編譯(separation compilation),即將程式分成多個檔案,每個檔案獨立編譯。
為了支援分離式編譯,必須將宣告(Declaration)和定義(Definition)區分開來。宣告是使得名字(Identifier,如變數名)為其它程式所知。而定義則負責建立與名字(Identifier)相關聯的實體,如為一個變數分配記憶體單元。因此只有定義才會申請儲存空間。
One definition rule(ODR):只能定義一次,但可以多次宣告
如果想要宣告一個變數而非定義它,就在前面加關鍵字extern,而且不要顯示地初始化變數:
extern int i; //變數的宣告
int i;//變數的定義(雖沒有顯示初始化,但會有初始值並分配記憶體單元儲存,即使初始值隨機)
任何包含顯式初始化的宣告成為定義。如果對extern的變數顯式初始化,則extern的作用被抵消。
extern int i = 0; //變數的定義
宣告和定義的區別非常重要,如果要在多個檔案中使用同一個變數,就必須將宣告和定義分離,變數的定義必須且只能出現在一個檔案中,而其他用到該變數的檔案必須對其宣告,而不能定義。
例如,標頭檔案裡不要放定義,因為標頭檔案可能會被到處include,導致定義多次出現。
值得一提的是C++17引入了 inline 變數,這允許在多個翻譯單元中定義同一個全域性變數而不引發重複定義的連結錯誤。inline 變數使得變數像 inline 函式一樣,在多個檔案中共享同一個定義。
而在之前的標準中,inline只能用於函式而不能用於變數
// header.h
inline int globalVar = 42;
關於其作用,可見C++17之 Inline變數
此外, C++20 引入了模組(Modules)機制,用於替代標頭檔案的傳統做法。模組減少了編譯依賴並提高了編譯速度。在模組中,變數宣告和定義的規則更為清晰,模組能夠很好地管理變數的可見性和作用範圍。
如有興趣,可見C++20 新特性: modules 及實現現狀
2.3.2 變數的初始化(C++11標準8.5節)
變數在建立時獲得一個值,我們說這個變數被初始化了(initialized)。最常見的形式為:型別 變數名=表示式;//表示式的求值結果為變數的初始值
用=來初始化的形式讓人誤以為初始化是賦值的一種。
其實完全不同:初始化的含義是建立變數時設定一個初始值;而賦值的含義是將變數的當前值擦除,而以一個新值來替代。
實際上,C++定義了多種初始化的形式:
int a = 0;
int b = { 0 };
int c(0);
int d{ 0 };
其中用{ }來初始化作為C++11的新標準一部分得到了全面應用(而以前只在一些場合使用,例如初始化結構變數)。這種初始化形式稱為列表初始化(list initialization)。