轉自:http://blog.kingsamchen.com/archives/697
0.NULL的前世今生
對於C和C++程序員來說,一定不會對NULL感到陌生。但是C和C++中的NULL卻不等價(別驚訝,這是真的)。
NULL表示指針不指向任何對象,但是問題在於,NULL不是關鍵字,而只是一個宏定義(macro)。
在C中,習慣將NULL定義爲void*指針值0:
#define NULL (void*)0
但同時,也允許將NULL定義爲整常數0
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
在C++中,NULL卻被明確定義爲整常數0:
#define NULL 0
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.
導致不同定義的根本原因是:隱式類型轉換(implicit conversion)。
C的定義使得存在void*到0的隱式類型轉換,而宏觀表現則是,void*指針可以直接賦值給其他的指針類型
int* ptr = 0;
int* pptr = (void*)0; // both are legal in c
但是C++卻不支持void*到其他類型的隱式轉換,所以上面的代碼在C++中並不能全部通過編譯。
1.C++的解釋
爲什麼C++在NULL上選擇不完全兼容C?原因和C++的重載函數有關。
C++通過搜索匹配參數的機制,試圖找到最佳匹配(best-match)的函數,而如果繼續支持void*的隱式類型轉換,則會帶來語義二義性(syntax ambiguous)的問題。
考慮下面兩個重載函數:
void foo(int i);
void foo(char* p)
foo(NULL); // which is called?
編譯器同時找到了兩個最佳匹配,以至於連編譯器都不知道選擇哪個。
爲了消除混亂,C++纔會將NULL定義爲整常數0。
但是,這麼做又帶來了另一個問題:NULL和整型發生了重疊。
2.C++的選擇
爲了徹底解決NULL帶來的問題,C++0x標準引入了一個新的關鍵字:nullptr。
nullptr是一個很神奇的關鍵字,他被定義爲std::nullptr_t類型,這是一個泛指針類型(這個術語是我自己加的-.-),支持到其他指針類型的自動轉換。並且不支持到除了bool類型以外的整型的轉換。
由於nullptr具有類型,且支持到任何兼容的指針類型的轉換,所以對於上述重載函數的調用,編譯器會很明確的選擇第二個函數。
不過,引入新關鍵字並不代表解決了一切問題。其代價也很明顯:向後兼容性/習慣性和編譯器的支持程度。
C++0x中保留了原來的NULL,所以舊的代碼也可以通過編譯。並且爲了和C保持最大程度的兼容,在一段時間內,NULL都應該是支持的。
至於程序員對於nullptr的接受程度,那隻能另當別論。
對於編譯器,Visual Studio 2010已經開始支持C++0x中的大部分特性,自然包括nullptr。而VS2010之前的版本,都不支持此關鍵字。
Codeblocks10.5附帶的G++ 4.4.1不支持nullptr,升級爲4.6.1後可支持nullptr(需開啓-std=c++0x編譯選項)
其餘編譯器對於nullptr的支持就不是太清楚了。有需要的可自行翻閱Wiki。
考慮到目前的編譯環境,用nullptr全面代替NULL不太現實,不過可以在文件頭加入說明或使用預編譯。