簡體   English   中英

是否需要將NULL轉換為結構指針類型以便在C中進行賦值/比較?

[英]Necessary to cast NULL to struct pointer type for assignment/comparison in C?

我的老師在將它轉換為指向結構foo的指針之前,一直將NULL轉換為(struct foo *) 例如:

struct foo {
   // smthg else
   struct foo *ptr;
};

struct foo *bar;
bar = (struct foo*)malloc(sizeof(struct foo));
bar->ptr = (struct foo *) NULL;

令我難以置信的是,他唯一一次測試該值是否為NULL(檢查鏈表是否已結束)他執行以下操作

if (aux->ptr != (struct foo *) NULL) {
   ...
}

我問他為什么,如果要“增長”NULL的大小以防止錯誤或其他什么。 但不,他告訴我(非常不情願,我認為)這是為了防止編譯器出現一些可能的錯誤(wtf?)。 這真的有必要嗎?

編輯:

他教的語言是C.他可能不知道用C語言鑄造malloc是不必要的。 我想知道他是否只是小心或無能。 :P

回答你的問題:不,沒有必要將NULL轉換為特定的指針類型。 編譯器為NULL了一個特殊情況,並允許將其分配給任何指針類型,而不指示指針類型轉換警告。

類似地,在與NULL進行比較時沒有必要進行強制轉換:

if (aux->ptr != NULL) {

正確的形式

struct foo *bar = (struct foo*)malloc(sizeof(struct foo));

在C中總是如此

struct foo *bar = malloc(sizeof *bar);

你的教授是錯的,並且可能從嘗試在C ++中使用malloc中汲取了不良習慣(這通常是不贊成的,有充分的理由)。

在C中, malloc的結果不需要轉換為變量類型。 在C ++中,它必須是,否則你將得到一個編譯時錯誤(不能隱式地將void *轉換為your_class * )。

如果您的老師正在嘗試教您正確的編碼原則,則需要演員。 如果您的老師正在嘗試教您C語言准備C ++,則需要學習使用演員表。 對於老師說“為了防止編譯器出現一些可能的錯誤”,沒有什么“wtf” - 你應該更經常地聽取他的意見。 假設你的教授無知可能不是你要走的路。

沒有必要將NULL轉換為特定的指針類型,因為NULL的#defined為0.我能想到的唯一原因是教育,因為在編寫程序時記住對象和指針的類型是很好的。

在C ++中,您將使用nullptr進行初始化並使用g ++ -std = c ++ 0x進行編譯

最后,有必要在C ++中轉換malloc的返回值,而不是在C中。在C ++中,你應該使用'new'。

曾經有過#define NULL 0錯誤編譯器,並且0不是(C89)C標准所要求的空指針常量。 這些天,你不太可能遇到這樣的編譯器。

它曾經在諸如execl("cmd", "arg0", "arg1", NULL);上下文中execl("cmd", "arg0", "arg1", NULL); 因為NULL需要是一個空指針常量,但是......現在,NULL是一個空指針常量,因此即使在那里也不需要強制轉換。 對於賦值操作,您可以只寫0而不是轉換NULL。 execl()示例中,您不能只寫0; 這是一個int ,不一定是空指針常量。

這個問題的正確答案是你的老師沒有錯 ,他/她也不是無知的 他/她只是在教你良好的習慣。 使用顯式強制轉換不是必須的,但至少有兩個很好的理由可以解釋。

  1. 代碼可移植性

    使用顯式強制轉換確保您的代碼可以在ANSI C編譯器,ANSI前編譯器以及最重要的非ANSI C兼容編譯器之間移植 您的教師代碼不應生成任何編譯器,符合或不符合,過去,現在或將來的錯誤或警告。

    如果在任何早於ANSI C或不符合ANSI的平台上進行編譯,則編寫代碼:

    \n pMyObject = NULL;\n

    在某些系統上,可以生成編譯器警告:

    \n 警告:'='從'void *'轉換為'struct foo *'\n 警告:'='從'int'轉換為'struct foo *'\n

    編譯器警告的目的是提醒您潛在的問題,因此編譯甚至單個警告的代碼不應被視為生產質量代碼,除非使用顯式強制轉換修復警告。

  2. 代碼可讀性

    使用顯式轉換可以極大地提高可讀性。 例如,基於Microsoft Windows SDK采用以下實際示例:

    \n hMyWindow = CreateWindow(NULL,NULL,WM_OVERLAPPED,0,0,100,100,NULL,NULL,NULL,NULL);\n if(hMyWindow == NULL)\n     ...\n

    除非您參考Microsoft Windows SDK,否則很明顯您將無法理解傳遞給此函數的參數。 但是,如果我寫:

    \n hMyWindow = CreateWindow((LPCTSTR)NULL,(LPCTSTR)NULL,WM_OVERLAPPED,0,0,100,100,(HWND)NULL,(HMENU)NULL,(HINSTANCE)NULL,(LPVOID)NULL);\n if(hMyWindow ==(HWND)NULL)\n     ...\n

    然后我知道, 在瞬間 :1)變量hWindow的類型,2) CreateWindow()返回類型,3)每個函數參數的類型。 幾乎我需要知道的一切,以了解這些代碼,我不必掃描當前文件,或尋找另一個頭文件,或浪費時間瀏覽互聯網尋找API文檔。 這使代碼自我記錄 ,如果您處於許多沒有內置代碼瀏覽支持的非圖形環境之一,這一點尤其重要。

在ANSI C99(ISO / IEC 9899:1999,第6.5.16.1節)中,ANSI同意NULL指針常量的概念,並且將NULL指針常量賦值給類型化對象的指針是合法的。

然而,老師教你上述方法的真正原因是因為他/她就像任何好老師一樣,為現實世界做好准備,而在現實世界中,ANSI C標准不是法律。 它不必被遵循,並且在大多數情況下不遵循它。 如果要獲得財務利潤或市場份額,編譯器公司會忽略或擴展任何標准。 此外,現有許多專有計算機系統,其中一些是世界上最大的制造商,其中安裝了非ANSI C兼容的編譯器,並且用於編譯C程序,因為它們必須支持非標准硬件。

這就是為什么在執行任何涉及NULL指針操作時使用顯式NULL是一個非常好的習慣。 它將確保您的代碼可以快速理解,編譯干凈,並且可以在以后生活中遇到的各種平台和編譯器工具中按預期工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM