NULL和0的區別,nullptr的來歷

轉載自:https://www.cnblogs.com/malecrab/p/5569707.html

 

某些時候,我們需要將指針賦值爲空指針,以防止野指針。

 

有人喜歡使用NULL作爲空指針常量使用,例如:int* p = NULL;。

也有人直接使用0值作爲空指針常量,例如:int* p = 0;。

 

前者可能覺得:NULL作爲空指針常量,名字很形象,可讀性較強。

後者可能覺得:NULL並不是C/C++語言的關鍵字,而是一個在標準庫頭文件<stddef.h>中定義的宏,因此要使用NULL,可能需要直接或簡介地包含<stddef.h>頭文件,比較麻煩。

 

問題一:NULL與常數0值有何區別?

 

要弄清楚這個問題,我們採用問與答的形式來描述。

 

問:NULL到底是什麼?

 

答:NULL是一個宏。

 

問:它的值是多少?

 

答:C/C++標準規定:它的值是一個空指針常量(null pointer constant),由實現定義。#1,#2

 

問:什麼樣的值才能稱之爲空指針常量?

 

答:C語言中常數0和(void*)0都是空指針常量;C++中(暫且忽略C++11)常數0是,而(void*)0 不是。#3,#4

 

問:NULL宏是在哪裏定義的?

 

答:通常是在C標準庫的<stddef.h>頭文件中,不過別的頭文件中可能也有定義。

 

問:一般編譯器的<stddef.h>頭文件中NULL宏是如何定義的?

 

答:以gcc或clang編譯器爲例,NULL的定義大致如下(稍有簡化):

#if defined(__cplusplus)
# define NULL 0    // C++中使用0作爲NULL的值
#else
# define NULL ((void *)0)    // C中使用((void *)0)作爲NULL的值
#endif

 

問:爲什麼C中(void*)0是空指針常量,而C++中不是?

 

答:因爲C語言中任何類型的指針都可以(隱式地)轉換爲void*型,反過來也行,而C++中void*型不能隱式地轉換爲別的類型指針(例如:int*p = (void*)0;使用C++編譯器編譯會報錯)。#5,#6

 

問:既然C/C++標準中,常數0都可作爲空指針常量,爲什麼不統一使用0?

 

答:個人覺得由於(void*)0更能體現指針的意義,而常數0更多的時候是用作整數。因此,C語言中NULL定義選擇了(void*)0。(僅供參考)

 

問題二:C++11中爲什麼要引入nullptr?

 

考慮着這樣一個函數重載的情形:

 

#include <stddef.h>
void foo(int) {}     // #1
void foo(char*) {}   // #2
int main() {
    foo(NULL); // 調用#1還是#2?
}

 

 

從字面上來講,NULL是個空指針常量,我們可能會覺得:既然是個指針,那麼應該調用#2。但事實上調用的卻是#1,因爲C++中NULL擴展爲常數0,它是int型。

 

根本原因就是:常數0既是整數常量,也是空指針常量。

 

爲了解決這種二義性,C++11標準引入了關鍵字nullptr,它作爲一種空指針常量。#7例如:

 

void foo(int) {}     // #1
void foo(char*) {}   // #2
int main() {
    foo(nullptr); // 它會毫無異議地調用#2
}

 

附註:

 

[#1] C99: 7.17-p3:

    The macros are

        NULL

    which expands to an implementation-defined null pointer constant; and ...

 

[#2] C++03: 18.1-p4:

    The macro NULL is an implementation-defined C + + null pointer constant in this International Standard(4.10).

 

[#3] C99: 6.3.2.3-p3:

    An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

 

[#4] C++03: 4.10-p1:

    A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.

 

[#5] C99: 6.3.2.3-p1:

    A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

 

[#6] C++03: 4.10-p2:

    An rvalue of type “pointer to cv T,” where T is an object type, can be converted to an rvalue of type “pointer to cv void.”

 

[#7] C++11: 4.10-p1:

    A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t.

 

參考:

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章