日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

nullptr、NULL、null和0

發布時間:2023/12/31 综合教程 33 生活家
生活随笔 收集整理的這篇文章主要介紹了 nullptr、NULL、null和0 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C語言和C++對大小寫是敏感的,也就是說null和NULL是區別對待的。NULL代表空地址,null只是一個符號,null可以是自己定義的一個變量。


NUll是一個宏定義 #define NULL 0,容易產生宏常常產生的錯誤。


nullptr是C++11中才引入的一個字面值常量,可以被轉換成任意其他指針,其用法和直接用字面值0是一樣的。


以下不完全轉載至http://www.kiford.com/a/WZ012116VDNEF3BD?utm_source=tuicool&utm_medium=referral


在強調一下,NULL 在C++中的定義僅僅是 0,僅此而已。(切記,NULL 是宏,以下錯誤都是宏引起的)

當然,這看起來僅僅是語法問題啦。那么使用 nullptr 和 NULL 究竟有沒有差別呢?當然有! 使用 nullptr 可以幫助我們避免各式各樣的錯誤。

還是用實例來說明吧。

假設,有兩個被重載的函數:

void Foo(int x, int y, const char *name);

void Foo(int x, int y, int ResourceID);


我們可能像下面這樣來調用:

1.Foo(1, 2, NULL);


有些程序猿認為這樣寫調用的是第一個函數。結果卻不是這樣的,因為 NULL 僅僅就是 0,是int類型的 0,所以第2個函數會被調用,而不是第一個函數。


然而,如果使用的是 nullptr,那么第一個函數將被調用,就不會產生這種錯誤了。


另一個通常的使用 NULL 方式如下代碼所示:

if (unknownError)

throw NULL;


依我之見,拋出一個指針異常這件事兒就是令人懷疑的。不過有時一些人會這么做。顯然,開發者需要編寫這樣的代碼。好吧,討論這樣做的好與壞超出了本文的范疇。


重點是我們想在產生未知錯誤時拋出一個異常,并且要把一個空指針"送到"外部世界。但實際上送出去的不是指針,而是一個int類型。結果就是異常并不會像我們認為的那樣被捕獲 。


throw nullptr; 可以讓我們避免這種錯誤。但,好吧,這并不意味著我完全接受這種(拋出指針異常)的代碼。


在一些情況下,使用 nullptr 是會產生編譯錯誤的。


例如一些WinApi函數返回 HRESULT 類型的參數。HRESULT 類型和指針本沒什么關系,然而如下所示的這種渣渣代碼卻有可能被寫出來:

if (WinApiFoo(a, b, c) != NULL)


編譯沒有問題,因為 NULL 是int類型的0,HRESULT 是long型,比較類型int和long是可以的。如果使用 nullptr 呢,如下所示的代碼就編譯不過去啦:

if (WinApiFoo (a, b, c)! = nullptr)



如此,這個錯誤便能夠被立刻被發現并改正啦。


你肯定有這種想法,這種例子是有很多,但這都是你自己臆想的啊,這可不能說服大家。有沒有實際的例子呢?當然有,這就有一個,只不過不是那種短小精悍的例子。


這段代碼來自 MTASA。


有這么一個 RtlFillMemory() ,它可能是一個函數或者宏,這都不重要。它和 memset() 有點像,只不過第二個和第三個參數是顛倒的。他可能是這樣聲明的:

#define RtlFillMemory(Destination,Length,Fill)

memset((Destination),(Fill),(Length))



還有一個 FillMemory(),就是把 RtlFillMemory() 重定義了一下:

#define FillMemory RtlFillMemory



好吧,挺長挺亂的,但這確實是實際中的一個例子。

FillMemory 是這么被使用的:

LPCTSTR __stdcall GetFaultReason ( EXCEPTION_POINTERS * pExPtrs ){

....

PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol ;

FillMemory ( pSym , NULL , SYM_BUFF_SIZE ) ;

....

}



這段代碼bug不止一個。明顯的就是第2個參數和第3個參數用反了。這就是分析器報了兩個警告的原因 V575:

V575 The 'memset' function processes value '512'. Inspect the second argument. crashhandler.cpp 499 (memset 處理的值是'512',檢查一下第2個參數)

V575 The 'memset' function processes '0' elements. Inspect the third argument. crashhandler.cpp 499(memset 處理了0個元素,檢查一下第1個參數)


但錯誤可不止這一處:NULL 用在這壓根就不合適。memset() 函數是按字節填充的,所以使用 NULL 值來填充的想法就是錯(譯者注:雖然 memset 的第2個參數value是int型,但實現時會轉化成 unsigned char 來填充內存,參看memset文檔)。 來看看正確的代碼:

FillMemory(pSym, SYM_BUFF_SIZE, 0);


或者這樣:

ZeroMemory(pSym, SYM_BUFF_SIZE);


但這也不是重點,重點是這種渣渣代碼居然能
編~譯~成~功~。可是如果程序猿們習慣使用的是 nullptr 而不是 NULL,那么代碼就會寫成這樣:

FillMemory(pSym, nullptr, SYM_BUFF_SIZE);


這樣的話編譯器會拋出一個編譯錯誤,猿們就能意識到他們的錯了,就會多多注意他們的代碼了。

另外,我明白這種情況下不應該責備 NULL 本身,這只能怪代碼編譯時沒有拋出關于 NULL 的警告,我們的代碼應該盡可能讓編譯器來發現錯誤。

總結

以上是生活随笔為你收集整理的nullptr、NULL、null和0的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。