Wie ist die Initialisierung des Werts "int * ptr = int ()" nicht illegal?

86

Der folgende Code ( von hier übernommen ):

int* ptr = int();

Kompiliert in Visual C ++ und initialisiert den Zeiger mit einem Wert.

Wie ist das möglich? Ich meine, int()ergibt ein Objekt vom Typ intund ich kann inteinem Zeiger kein Objekt zuweisen .

Wie ist der obige Code nicht illegal?

scharfer Zahn
quelle
Keine Antwort, aber tolle Frage! Ich habe so etwas noch nie gesehen.
Josh
6
Da Grundelemente in C ++ einen 'Konstruktor' haben, int()ergibt sich der Wert konstruierter Wert von int(was meiner Meinung nach eine von C ++ 03 spezifizierte Sache ist) und der Standardwert von intist 0. Dies entsprichtint *ptr = 0;
wkl
7
@EmanuelEy: Nein, jede ganzzahlige Konstante mit Nullwert kann als Nullzeigerkonstante verwendet werden, unabhängig davon, wie Zeiger tatsächlich implementiert werden.
Mike Seymour
1
@MooingDuck: Ich habe nicht gesagt, NULLdass ein Wert ungleich Null sein könnte. Ich sagte, es könnte eine beliebige ganzzahlige Konstante mit Nullwert sein (einschließlich int()).
Mike Seymour
5
@ DanielPryden Das ist eine Verwendung des Wortes "Objekt", von dem ich vorher nichts wusste.
flauschige

Antworten:

110

int()ist ein konstanter Ausdruck mit dem Wert 0, daher ist dies eine gültige Methode zum Erzeugen einer Nullzeigerkonstante. Letztendlich ist es nur eine etwas andere Art zu sagenint *ptr = NULL;

Jerry Sarg
quelle
3
+1, das konstante Ausdrucksbit ist wichtig und fehlt in den Top-2-Antworten.
David Rodríguez - Dribeas
geht das mit C ++ 0x weg?
Neil G
@NeilG: Dies bleibt in C ++ 11 gleich, obwohl es jetzt auch eine gibt nullptr, die Sie anstelle von 0oder NULLin neuem Code verwenden können.
Jerry Coffin
2
@Nils: Klarheit des Codes und Erklärung Ihrer Absicht durch Code. Natürlich möchten Sie mit C ++ 11 jetzt nullptr verwenden, da dies auch den Vorteil zusätzlicher Überprüfungen zur Kompilierungszeit in den Mix bringt.
Jamin Gray
3
@Nils, weil ganz offensichtlich 0eine Nullzeigerkonstante oder die Zahl 0 bedeuten könnte, während nullptroffensichtlich eine Nullzeigerkonstante ist. Darüber hinaus gibt es, wie Jamin sagte, auch "zusätzliche Überprüfungen zur Kompilierungszeit". Versuchen Sie zu überlegen, bevor Sie tippen.
Miles Rout
35

weil int() Ausbeuten 0, die austauschbar sind mit NULL. NULLselbst ist definiert als 0, im Gegensatz zu Cs, NULLdie ist (void *) 0.

Beachten Sie, dass dies ein Fehler wäre:

int* ptr = int(5);

und das wird noch funktionieren:

int* ptr = int(0);

0ist ein spezieller konstanter Wert und kann daher als Zeigerwert behandelt werden. Konstante Ausdrücke, die ergeben 0, wie z. B. 1 - 1Nullzeigerkonstanten.

Blagovest Buyukliev
quelle
1
Beachten Sie auch, dass Cs NULL auch nicht unbedingt ist (void *)0. Es ist einfach eine Implementierung, die als "ganzzahliger konstanter Ausdruck mit dem Wert 0 oder ein solcher Ausdruck vom Typ void *" definiert ist.
Jerry Coffin
@ JerryCoffin Ich habe noch nie einen C-Compiler verwendet, der definiert ist NULLals (void*)0; es war immer 0(oder vielleicht 0L). (Aber als C90 (void*)0in C legalisiert wurde, verwendete ich bereits C ++.)
James Kanze
1
@JamesKanze: In Ubuntu 11.04 und unserer eigenen Linux-Version enthält libio.h: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)Die aktuelle Version von gcc in Ubuntu ist 4.5, in unserem System ist 4.0.
David Rodríguez - Dribeas
5
" 0ist ein spezielles Literal" - nur weil es ein konstanter Ausdruck ist und den speziellen Wert 0 hat. (1-1)ist ebenso speziell, es ist auch eine Nullzeigerkonstante und so ist es auch int(). Die Tatsache 0, ein Literal zu sein, ist ausreichend, aber keine notwendige Bedingung, um ein konstanter Ausdruck zu sein. Etwas wie strlen(""), obwohl es auch den speziellen Wert hat 0, ist kein konstanter Ausdruck und daher keine Nullzeigerkonstante.
Steve Jessop
@SteveJessop: Ich stimme der Korrektur zu, es geht wirklich um den konstanten Wert 0, nicht um das 0Literal.
Blagovest Buyukliev
18

Der Ausdruck int()ergibt eine konstante standardmäßig initialisierte Ganzzahl, die der Wert 0 ist. Dieser Wert ist etwas Besonderes: Er wird verwendet, um einen Zeiger auf den NULL-Status zu initialisieren.

Mark Ransom
quelle
2
Diesem fehlt ein sehr wichtiges Detail in Jerrys Antwort: Es reicht nicht aus, dass der Ausdruck den Wert 0 ergibt, sondern er muss auch ein konstanter Ausdruck sein . Für ein Gegenbeispiel mit int f() { return 0; }gibt der Ausdruck f()den Wert 0 aus, kann jedoch nicht zum Initialisieren eines Zeigers verwendet werden.
David Rodríguez - Dribeas
@ DavidRodríguez-dribeas, in meiner Eile, eine Antwort in möglichst einfachen Worten zu präsentieren, habe ich diesen Teil weggelassen. Ich hoffe es ist jetzt akzeptabel.
Mark Ransom
13

Ab n3290 (C ++ 03 verwendet ähnlichen Text), 4.10 Zeigerkonvertierungen [conv.ptr] Absatz 1 (der Schwerpunkt liegt bei mir):

1 Eine Nullzeigerkonstante ist ein integraler Konstantenausdruck (5.19) vom Wert Integer, der als Null ausgewertet wird, oder ein Wert vom Typ std :: nullptr_t. Eine Nullzeigerkonstante kann in einen Zeigertyp konvertiert werden. Das Ergebnis ist der Nullzeigerwert dieses Typs und kann von jedem anderen Wert des Objektzeiger- oder Funktionszeigertyps unterschieden werden. Eine solche Konvertierung wird als Nullzeigerkonvertierung bezeichnet. [...]

int()ist ein solcher integraler konstanter Ausdruck prvalue vom Integer-Typ, der Null ergibt (das ist ein Schluck!) und somit zum Initialisieren eines Zeigertyps verwendet werden kann. Wie Sie sehen können, 0ist dies nicht der einzige integrale Ausdruck, der in einem speziellen Gehäuse steht.

Luc Danton
quelle
4

Nun, int ist kein Objekt.

Ich glaube, was hier passiert, ist, dass Sie dem int * sagen, dass er auf eine durch int () bestimmte Speicheradresse verweisen soll.

Wenn also int () 0 erstellt, zeigt int * auf die Speicheradresse 0

Megatron
quelle
1
int()ganz sicher ist ein Objekt.
Leichtigkeitsrennen im Orbit
@Tomalak: Ich glaube nicht. Es ist ein temporärer Typ ohne Klasse, und ich glaube, ich kann zu Recht sagen, dass dies keine Objekte sind, was den C ++ - Standard betrifft. Es ist jedoch etwas seltsam, dass der Abschnitt über "temporäre Objekte" zunächst nur über temporäre Objekte des Klassentyps spricht, später jedoch über das Binden von Referenzen, und natürlich können Sie eine Referenz an binden int(). Definieren int i;, dann keine Frage, iist ein Objekt.
Steve Jessop
@Steve: Ich würde nur eine Debatte darüber erwarten, dass "Objekte" eine Speicherregion in C ++ sind und Provisorien nicht wirklich Speicher haben, oder? 1.8 / 1 listet Provisorien nicht explizit auf, aber es scheint, als ob die Absicht besteht, sie einzuschließen.
Leichtigkeitsrennen im Orbit
1
@Tomalak: Ja, in der Tat benötigen Provisorien vom Nicht-Klassentyp keinen Speicher, es sei denn, Sie nehmen eine Referenz. Egal, es spielt keine Rolle. Die Aussage "well int ist kein Objekt" ist nur wahr, weil intes sich um einen Typ handelt, nicht um ein Objekt. Ob sich int()ein Objekt oder nur ein Wert ergibt, hat keinen Einfluss auf irgendetwas, was jemand anders gesagt hat.
Steve Jessop
@Steve: So viel ist unbestreitbar :)
Leichtigkeitsrennen im Orbit