Ich habe mit herumgespielt gcc
und habe folgenden Code ausprobiert:
int A = 42;
int *B = &A;
int *C = &*B;
Und C == &A
, wie erwartet. Aber wenn ich es versuche:
int *B = NULL;
int *C = &*B;
Es stellt sich heraus C == NULL
, und kein segfault. So &*B
dereferenziert nicht wirklich B
bevor er seine Adresse nimmt.
Meine Vermutung ist, dass der Präprozessor Instanzen von entfernt &*
und *&
bevor sie überhaupt zum Compiler gelangen, da sie sich gegenseitig negieren, aber ich kann keine Dokumentation finden, um zu überprüfen, ob dies Standard ist C oder Compiler-spezifisch.
Strippt der Präprozessor &*
und *&
und kann ich dieses Verhalten von einem bestimmten Compiler erwarten?
Dies wird nicht vom Vorprozessor entfernt, &*
am Ende nur dem Zeiger selbst entspricht, wir können dies sehen, indem wir zu gehen Entwurf des C99-Standards 6.5.3.2
Adress- und Umleitungsoperatoren Absatz 4 was sagt:
Der unäre *-Operator bezeichnet die Indirektion. Wenn der Operand auf eine Funktion zeigt, ist das Ergebnis ein Funktionsbezeichner; Wenn es auf ein Objekt zeigt, ist das Ergebnis ein lvalue, der das Objekt bezeichnet. Wenn der Operand vom Typ „Zeiger auf Typ“ ist, hat das Ergebnis den Typ „Typ“. Wenn dem Zeiger ein ungültiger Wert zugewiesen wurde, ist das Verhalten des unären *-Operators undefiniert.87)
und Fußnote 87 sagt:
Somit ist &*E äquivalent zu E (auch wenn E ein Nullzeiger ist),[…]
und Absatz 3 sagt (Betonung von mir):
Der unäre &-Operator liefert die Adresse seines Operanden. Wenn der Operand vom Typ ”Typ” ist, hat das Ergebnis den Typ ”Zeiger auf Typ”. Wenn der Operand das Ergebnis eines unären *-Operators ist, wird weder dieser Operator noch der &-Operator ausgewertet und das Ergebnis ist so, als ob beide weggelassen würdenaußer dass die Einschränkungen für die Operatoren weiterhin gelten und das Ergebnis kein Lvalue ist.
Aktualisieren
Es lohnt sich wahrscheinlich, das zu beachten gcc
und clang
Sie können die Ergebnisse der Vorverarbeitung anzeigen, indem Sie verwenden -E
Flagge(live sehen) und in Visual Studio /EP(live sehen).
Erwähnenswert ist auch, dass MSalters in seinem Kommentar sagte, dass er nur die beiden Token hat &*
reicht nicht aus, um den Zusammenhang zu verstehen, wie sein Beispiel zeigt:
int *p, *q ;
int foo = *p & *q ;
Also einfach entfernen &*
nicht einmal während der Vorverarbeitung möglich, da Ihnen nicht genügend Informationen zur Verfügung stünden, um festzustellen, ob &
war das Adresse von Betreiber bzw bitweise und Operator.
Der Präprozessor wird nicht ausgeblendet &*
. Der C 2011-Standard sagt jedoch in 6.5.3.2 3, ungefähr &
:
Wenn der Operand [of &] ist das Ergebnis eines unären * Operator, weder dieser Operator noch der & Operator wird ausgewertet und das Ergebnis ist so, als ob beide weggelassen würden, außer dass die Einschränkungen für die Operatoren weiterhin gelten und das Ergebnis kein L-Wert ist.
Wie von den oben erwähnten Beschränkungen gefordert, ist der Operand von * muss Zeigertyp haben. Daher, &*3
wird nicht geändert 3
durch diese Klausel; es verstößt gegen die Beschränkungen, weil 3
hat keinen Zeigertyp. Zusätzlich, &*x
nicht ganz geändert x
, da das Ergebnis kein Lvalue ist. Nicht erlaubt sind beispielsweise:
int a, *x;
x = &a; // Normal, allowed.
&*x = &a; // Not allowed; `&*x` does not became exactly the same as `x`.
Der Compiler könnte diese Anweisung optimieren, aber ich bezweifle, dass der Präprozessor dies tun würde.
– Annäherung an DarknessFish
21. Januar 2014 um 1:22 Uhr
Es wird vom Vorprozessor nicht “gestrippt”. Es ist der Compiler selbst, der das erkennt
&*
ist ein no-op.– Heiße Licks
21. Januar 2014 um 1:25 Uhr
Dies ist ein undefiniertes Verhalten. Der Optimierer hat Ihren Code zufällig so verarbeitet, dass nichts Katastrophales passiert ist, aber der Computer kann segfaulten, später ausfallen oder Dämonen aus Ihrer Nase fliegen lassen.
– Benutzer2357112
21. Januar 2014 um 7:27 Uhr
Der Präprozessor entfernt es besser nicht:
int *p, *q; int foo = *p & *q;
– vollkommen legaler Code, aber nur der Compiler kann erkennen, dass es sich um den binären Operator handelt.– MSalter
21. Januar 2014 um 8:33 Uhr
Es ist viel darüber gesagt worden
&*
jetzt. Aber du fragst auch danach*&
was trivial, weil ungefährlich ist: if&
ist erlaubt, es ist sicher, es wieder zu dereferenzieren, machen*&
auch ein Noop. Da bei diesem Vorgang aber nichts passieren kann, bedarf es keiner besonderen Behandlung.– glglgl
21. Januar 2014 um 9:28 Uhr