在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 年齡;

如果閱讀你的程式碼的人懂漢語,而你英文實在不是很好,用漢語起名字也未嘗不是一種選擇,當然前提是你的編譯器要支援。