2016-04-27 42 views
2
#include <iostream> 
int main() 
{ 
    int *ptr = NULL; 
    // It does not crash 
    *ptr; --------> Point-1 
    //But this statment crashed 
    std::cout<<"Null:"<<*ptr<<"\n"; ------> Point-2 
    return 0; 
} 

在上面的代碼中,當我評論「Point-2」時,代碼不會崩潰。 但是,當我取消註釋「Point-2」時,它被撞毀。 由於理想情況下ptr爲NULL,Point-1也應該崩潰。請糾正我,如果我錯了。 有人可以解釋我爲什麼代碼不會崩潰時,我只是dereffernece指針?爲什麼簡單地用一個指針指向NULL的引用不會崩潰

+2

在沒有優化的調試模式下編譯並重試.. – BlackBear

+2

停止假定調用*未定義的行爲*導致*定義的行爲*。它沒有。事實是,如果你是幸運的,它就會崩潰,你真的得想看到它理解爲什麼這是真的。 – WhozCraig

+2

供您參考: - http://stackoverflow.com/questions/12645647/what-happens-in-os-when-we-dereference-a-null-pointer-in-c – ravi

回答

2

解引用空指針是未定義的行爲。未定義的行爲不等於錯誤。如果觸發未定義的行爲,可能會發生任何事情。如果你問另一種方式:

爲什麼未定義的行爲不會導致錯誤而不是給我們奇怪的行爲?

這可能是由於很多原因。一個原因是性能。例如,在執行std::vector(至少在MSVC中)時,不會檢查發佈模式下索引是否爲超出範圍。你可以嘗試這樣做:

std::vector<int> v(4); 
v[4]=0; 

它會編譯並運行。你可能會有奇怪的行爲,或者你可能不會。但是,在調試模式下,它將在運行時拋出異常。 MSVC在調試模式下進行檢查,因爲在調試模式下性能不重要。但它並不處於發佈模式,因爲性能很重要。

這同樣適用於取消引用空指針。你可以形象,提領的代碼將被放在一個包裝這樣的:

//Imaginary code 
T& dereference(T* ptr){ 
    if(ptr==nullptr){ 
     throw; 
    } 
    return *ptr; 
} 

這一部分:if(ptr==nullptr){throw;}將放緩每個指針的解引用過程中這是不可取的上下文。

但是,它可能就像這樣:

//Imaginary code 
T& dereference(T* ptr){ 
    #ifdef DEBUG 
    if(ptr==nullptr){ 
     throw; 
    } 
    #endif 
    return *ptr; 
} 

我覺得你有這個想法了。

+0

我會將第二句稱爲「未定義的行爲不等於崩潰」(它*是*錯誤 - 不一定被捕獲的錯誤)。 –

+0

雖然你說的是真的,但我認爲在這種特殊情況下,訪問不會發生,因爲它正在被優化。 –

+0

@MartinBonner嗯,我不知道真的..是錯誤,通過定義,東西是不正確的?不應該至少觸發它?我不是意味着被抓住了,只是觸發了?未定義的行爲可能不會觸發任何事情。對? –

0

在第2點,您嘗試顯示0x0地址的內容,這會產生訪問衝突錯誤。

在第1點,你什麼都不做,所以程序不必訪問這個指針描述的內存。這不會產生訪問違規錯誤。

+0

看不出爲什麼這是被低估了。我認爲這是完全正確的。 –

+0

@MartinBonner它沒有解釋*爲什麼程序不需要訪問內存。例如,如果取消引用NULL指針有一些定義的行爲,那麼通過刪除訪問進行優化將是非法的(因爲您不會獲得您應該得到的行爲)。這是因爲UB可以刪除訪問。 –

+1

@DavidSchwartz:那是錯誤的。訪問可以被優化,因爲解引用非易失性指針沒有副作用。它與UB完全沒有關係。如果代碼是'int i = 42,* ptr =&i; * ptr;',編譯器仍然可以優化訪問。 –

相關問題