在C++11(C++0x)里,空指針有了一個官方版的表示:nullptr。在此之前C++里的空指針應該怎么表示呢?
一種方法是定義一個NULL宏(#define NULL 0)來表示空指針,雖然本質上和直接寫成0一樣,但NULL能相對直觀地表示這是個指針。
一些知名頭文件里就帶有NULL的定義,比如windows.h和stdio.h。直接用NULL似乎是個不錯的主意。
有時候源文件中並不需要引用到這些知名頭文件,那么NULL就要由自己來定義。這樣,可能在很多地方都充斥着NULL的定義,看着就覺得不是很痛快。另外,NULL可以由自己定義,這意味着NULL完全有可能被定義成其他東西(少見)。因為NULL並非標准,所以有人可能自己定義了Null或null或其他東西(少見),這會帶來混亂。
那么直接用0來表示空指針好了。用0表示寫起來簡單,而且0就是0,不會有其他定義,只是不那么直觀。
但是用0也好,用NULL也好,都有一個先天劣勢,就是在類型匹配時它會被優先當成整數,在一些情況下會帶來麻煩。比如:
void fun(int*) { std::cout << "pointer" << std::endl; } void fun(int) { std::cout << "int" << std::endl; }
上面的fun有兩種重載形式,一種是以整數為參數,一種是以整數指針為參數。假設現在,想要傳空指針給fun,要怎么寫。
寫成fun(0),毫無疑問,這里打印的會是“int”,因為0被當成一個整數。為了讓它調用第一個版本的函數,我們需要明確的傳遞一個指針,寫成fun((int*)0),函數調用正確。
假設還有一個fun(char*)版本的函數,那豈不是要寫成fun((char*)0)。吹毛求疵的人可能會覺得這樣不好,因為空指針的表示不一致,需要根據不同情況做強制轉化。
這時,NULL又被想起,我們可以這樣定義#define NULL ((void*)0),這樣NULL就真真切切是個指針了。在C語言里,這是行得通的。可惜這在C++里不行,因為C++中void*並不能隱式轉換成int*或其他類型的指針。仍舊需要fun((int*)NULL)和fun((char*)NULL),這樣更丑。
既然強制轉換無可避免,相比之下,還是0好一點。
但實際上前面提到的兩種方法不只不恰當,嚴格來說還不准確。早期C++著作The Annotated C++ Reference Manual(ARM)里指出:“Note that the null pointer need not be represented by the same bit pattern as the integer 0.”也就是說空指針並不一定是0。因此不管是直接寫成0,還是用宏來表示都不准確的。只是大多數人(包括我)一直這么用,也一直沒出什么問題。
工作時因為項目早期代碼基本都是采用NULL,為了保持編碼風格的一致性,我也一直沿用這一寫法。
而平時偶然寫代碼則更傾向於直接使用0,最直接的原因是每次要使用NULL時都要關注一下它是不是已經不定義了,在沒定義的情況下自己還要定義一個,感覺挺麻煩的。
總的結論是:具體的選擇只是看個人喜好。
