2017-11-11 5 views
2

betrachten den CodeErklärungen über NULL, 0, nullptr

#include <iostream> 

void foo(int* p) 
{ 
    std::cout << "pointer" << '\n'; 
} 

void foo(int p) 
{ 
    std::cout << "value" << '\n'; 
}  

int main() 
{  
    foo(0); // value 
    foo(NULL); // error: call of overloaded ‘foo(NULL)’ is ambiguous foo(NULL); 

    return 0; 
} 

Hier haben wir ein Problem mit der Auswahl eine richtige Überlast für Null-Zeiger sehen können, die indem nullptr zu einem zweiten Aufruf der Funktion gelöst werden können foo , aber meine Frage ist etwas anders ...

da ich die meisten Implementierungen definieren NULL als nur eine konstante wörtliche 0 wie (#define NULL 0) wusste, daher ist es bei der Kompilierung erwartet wird, ein zweiter Aufruf wie folgt zu haben - foo(0),

Aber die Präprozessor gibt einigen seltsamen Ausgang (nach g++ -std=c++11 -E main.cpp -o main läuft)

int main() 
{ 

foo(0); 

foo(
# 25 "main.cpp" 3 4 
    __null 
# 25 "main.cpp" 
     ); 

return 0; 
} 

Was __null hier ist ??

Ist das ein eingebauter Int-Typ?

+3

Sieht so aus, als ob das implementierungsspezifisch ist (beachte das '__'). Welchen Compiler benutzen Sie? – user0042

+0

@ user0042 Ich benutze 'g ++ 5.4.0' – ampawd

+0

https://gcc.gnu.org/onlinedocs/libstdc++/manual/support.html (letzter Absatz) Mit anderen Worten, das' _null' magic Schlüsselwort soll Verhindere genau das, was du siehst (zuerst betrachte man "0" als Integer und wandelt es dann erst in "nullptr" um). – Damon

Antwort

3

__null ist ein Compiler integriert. GCC verwendet es, um bessere Diagnosen zu geben. Das Problem ist, dass man wirklich NULL als

#define NULL ((void *) 0) 

definieren wollen - genau wie in C. Aber mit aktuellen C++, würden Sie nicht in der Lage sein

int *p = NULL; 

zu schreiben, weil im Gegensatz zu C, gibt es keine implizierte Konvertierung von void * zu anderen Zeigertypen. So implementiert GCC __null als eine magische Null-Zeiger-Konstante, die für jeden beliebigen Zeigertyp gültig ist, aber keine Ganzzahl ist. Als Ergebnis kann GCC Warnungen ausgeben, die sonst nicht möglich wären.

Im Wesentlichen ist __null eine frühe Version von nullptr, aber es ist konservativer, weil es nur eine Erweiterung ist, keine Sprachveränderung.