The New C++ -- 變數(1. 變數的宣告和定義)
阿新 • • 發佈:2019-01-02
在C++中,不僅僅是變數才有名字,列舉(enumeration),函式(function),類(class),模板(template)等物件都有名字。在使用任何一個名字之前,必須要先對該名字表示的物件進行宣告(declaration)或者定義(definition)。宣告和定義這兩個詞的經常容易被混淆,有時用一個名字只需要該名字的宣告就可以了,有時用一個名字需要該名字的定義。並且不同型別的物件(變數,列舉,函式,等等)的宣告和定義的概念也不太相同,本系列文章中會對他們進行明確的區分。C++中的定義和宣告的區別是符合我們的對事物理解的經驗和直覺的,所以絕大多數情況下並不需要特別記憶。
對於變數來說,宣告一個變數即是相當於告訴編譯器兩個資訊:變數名和其相對應的變數型別。定義一個變數即使相當於告訴編譯器變數名和變數型別,同時讓編譯器在記憶體中預留該變數的儲存空間(因為預留空間是編譯器自動完成的,所以編譯器自然也自動知道了該變數的首地址)。可以看到定義一個變數得同時讓這個變數在記憶體中也真正存在了,而宣告一個變數名卻沒有這個要求。變數的定義也是一個宣告(簡單來說,就是宣告再加上在記憶體中預留空間),但是變數的宣告不一定是定義。
我們可以用下面的語法來定義(也是宣告)一個變數。
變數型別說明符 變數名1, 變數名2, ... , 變數名3;
其中變數型別說明符的作用是告訴編譯器該變數的型別。我們上節提到過的基本資料型別的變數型別說明符如下表,
基本資料型別 | 變數型別說明符 |
char | char |
unsigned char | unsigned char |
signed char | signed char |
char16_t | char16_t |
char32_t | char32_t |
wchar_t | wchar_t |
unsigned short int | unsigned short, unsigned short int |
short int | signed short, signed short int, short, short int |
unsigned int | unsigned int, unsigned |
int | signed int, signed, int |
unsigned long int | unsigned long int, unsigned long |
long int | signed long int, signed long, long int, long |
unsigned long long int | unsigned long long int, unsigned long long |
long long int | signed long long int, signed long long, long long int, long long |
bool | bool |
float | float |
double | double |
long double | long double |
要注意的是,整型可能對應多種型別說明符,他們之間是完全等價的。主要原因是signed和int可以忽略不寫。例如short int型別的型別說明符就是signed short int,int忽略不寫就變成signed short,signed忽略不寫就變成short int,signed和int都忽略不寫就變成short。下面的程式定義了(也是宣告)6個int型別的變數,變數名為var1,var2,...,var6。
int var1;
signed var2;
signed int var3;
int var4, var5, var6;
變數名(適用於其他的名字,包括函式名,類名,模板名等)是我們自己取的,但要注意有以下規則。第一,變數名的首字母必須為26個英文字母的大小寫外加下劃線,其他字母必須為26個英文字母的大小寫,加下劃線以及數字。舉例如下。
正確的變數名:my_age, NumOfProgrammers2012錯誤的變數名:2012population, coordinates?
第二,變數名不可以是下列C++中預留的關鍵詞。我們已經見過其中的一些關鍵詞,例如signed,unsigned,int,double等。其他關鍵詞我們會在後面的章節講解。
alignas continue friend register true
alignof decltype goto reinterpret_cast try
asm default if return& typedef
auto delete inline short typeid
bool double int signed typename
break do long sizeof union
case dynamic_cast mutable static unsigned
catch else namespace static_assert using
char enum new static_cast virtual
char16_t explicit noexcept struct void
char32_t export nullptr switch volatile
class extern operator template wchar_t
const false private this while
constexpr float protected thread_local
const_cast for public throw
第三,C++標準規定,所有以2個下劃線開頭的名字,以及1個下劃線加上1個大寫字母開頭的名字,例如__range,__Range或者_Range你的程式中都不可以用,因為要為標準庫預留。所有以1個下劃線開頭並且第二個字元並不是下劃線,也不是大寫字母的名字,例如_range,在你的程式中不可以用在全域性名字空間(對變數來說,在全域性名字空間的變數也叫做全域性變數)。全域性變數和全域性名字空間我們稍後再提。如果你就是用了這些名字,編譯器可能不會報錯,但是你的程式的可移植性就變差了,因為換到另外一個編譯器,就可能和另外一個編輯器的庫實現由名字衝突。
第四,在C++中,名字是大小寫敏感的。即大寫字母的名字和小寫字母的名字是不同的名字。例如,age,Age,AGE是3個不同的名字。
第五,本系列文章並不打算對如何命名作出規範。事實上每一個公司,每一個專案都可能有不同的命名規範。但是最基本的一條原則要牢記:我們給變數取的名字一定要是描述性的(也適用於其他物件的名字)。意思就是說,無論是你自己,還是維護你程式碼的人,一看到一個名字就要知道這個變數是做什麼的。一些名字例如average_salary,maxMathScore都是好名字。不要為了自己方便而取一些類似於a,b,c之類的名字,這樣的程式碼的維護性是很差的。
小知識:其實C++中,不僅僅是26個英文字母的大小寫,0-9的數字和下劃線可以用在名字上,Unicode也可以用在名字上。例如,你可以,
int \u5e74\u9f84;
如果你的編譯器支援當地語言到Unicode的轉化,上面的名字也可以這樣寫,
int 年齡;
如果閱讀你的程式碼的人懂漢語,而你英文實在不是很好,用漢語起名字也未嘗不是一種選擇,當然前提是你的編譯器要支援。