前言
C和C++的變量名是對大小寫敏感的斧散,因此NULL和null并不是一回事,前者是C/C++中的系統(tǒng)關(guān)鍵字颅湘,null并不是。C++11以后又引入了nullptr瞻鹏,用以解決NULL在隱式轉(zhuǎn)換和作為函數(shù)傳入?yún)?shù)時的二義性問題鹿寨。
在C++11以前,在C/C++語言中脚草,我們常常用NULL作為指針變量的初始值。而在C++11之后埂淮,卻不建議你這么做写隶。
其實NULL根據(jù)命名全大寫可以看出來,它是一個常量慕趴,既然是常量鄙陡,就需要進(jìn)行宏定義躏啰。C語言的標(biāo)準(zhǔn)頭文件是這樣定義的
#define NULL ((void*)0)
而到了C++中,則變成了
#define NULL 0
查閱stddef.h毫捣,可以看到如下定義
#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
從定義中可以看出想际,C++中溪厘,NULL其實就是0,但是也可以用作空指針畸悬,只是用作空指針可能是為了兼容C,迫于無奈披粟。
以下一段代碼可以很好地解釋NULL存在的問題:
#include<iostream>
using namespace std;
void test(void *p)
{
cout<<"p is pointer "<<p<<endl;
}
void test(int num)
{
cout<<"num is int "<<num<<endl;
}
int main(void)
{
test(NULL);
return 0;
}
這時冷冗,如果編譯的話,會報以下錯誤蒿辙,
$ g++ -o test test.cpp
main.cpp: In function ‘int main()’:
main.cpp:14:14: error: call of overloaded ‘test(NULL)’ is ambiguous
test(NULL);
很明顯,NULL存在二義性俺叭,它既是整數(shù)泰偿,也是一個指針,函數(shù)test()無法根據(jù)參數(shù)的數(shù)據(jù)類型判斷應(yīng)該調(diào)用哪一個實現(xiàn)耗跛。
這時使用nullptr的優(yōu)越性就體現(xiàn)出來了,因為它可以很好地把空指針這一層意思給剝離出來牍氛。nullptr就是C++11為了解決這個痛點而推出的東西烟阐。
test(nullptr);
就會自然而然地走到指針的那個函數(shù)里紊扬。因此唉擂,以后若想使用整數(shù)特性,就賦值為0玩祟,若想使用指針特性,就賦值為nullptr藏鹊,這樣一目了然转锈,減少了未知的Bug的可能性。
多說一句撮慨,為什么要作此改動,我想首先應(yīng)該是C和C++在處理void 類型的時候存在一定的區(qū)別影涉。C語言中规伐,void 類型的變量可以賦值給任意類型的指針,也可以被任意類型的指針賦值猖闪,兩個方向都不會報錯。但是C++具有更嚴(yán)格的類型檢查岔留,前者是不被允許的检柬。
因此下面一段C語言代碼是可以編譯通過的
int main()
{
void* a;
int* b=a;
}
但是下面的C++代碼就會報錯
test.cpp:4:7: error: cannot initialize a variable of type 'int *' with an lvalue of type 'void *'
int* b=a;
與此同時,在malloc上里逆,也存在類似的問題:
int len = 100;
int p = malloc(len * sizeof(int)); // C推薦做法
int p = (int )malloc(len * sizeof(int)); // C++推薦做法
malloc函數(shù)返回值得類型是 void*用爪,C不要求強(qiáng)制類型轉(zhuǎn)換,會自動進(jìn)行隱式轉(zhuǎn)換偎血,但是C++則需要盯漂,因為void* 不能轉(zhuǎn)換成其他類型的指針笨农。