Zeigersyntax in C: Warum gilt * nur für die erste Variable?
Lesezeit: 7 Minuten
Die folgende Deklaration in C:
int* a, b;
wird erklären a als Typ int* und b als Typ int. Ich bin mir dieser Falle bewusst, aber was ich wissen möchte, ist warum es funktioniert so. Warum erklärt es nicht auch b wie int*, wie die meisten Menschen intuitiv erwarten würden? Mit anderen Worten, warum * gelten für den Variablennamen und nicht für den Typ?
Sicher, Sie könnten es so schreiben, um konsistenter zu sein, wie es ist eigentlich funktioniert:
int *a, b;
Allerdings denke ich und jeder, mit dem ich gesprochen habe, in Begriffen von a ist vom Typ “Zeiger auf int”statt a ist ein Zeiger auf einige Daten und der Typ dieser Daten ist “int”..
War das einfach eine schlechte Entscheidung der Designer von C oder gibt es einen guten Grund, warum es so geparst wird? Ich bin mir sicher, dass die Frage schon einmal beantwortet wurde, aber ich kann sie nicht über die Suche finden.
Um ehrlich zu sein, wenn die C-Sprache das gemacht hat * Ändern Sie den Typ, dann würden die Leute fragen: “Warum nicht int *a, b; Gib mir einen Zeiger und eine Ganzzahl?”.
– bta
15. Juli 2010 um 23:46 Uhr
@bta, ja, würden wir – aber ich denke, es hätte weniger Leute verwirrt. Jedenfalls geht es nicht darum, über die Entscheidung zu streiten, die vor 40 Jahren getroffen wurde, sondern nur darum, zu verstehen, ob es Gründe dafür gibt, die mir nicht bekannt sind.
C-Deklarationen wurden auf diese Weise geschrieben, damit “Deklarationsspiegel verwendet werden”. Aus diesem Grund deklarieren Sie Arrays wie folgt:
int a[10];
Würden Sie stattdessen die Regel haben, die Sie vorschlagen, wo sie immer ist
type identifier, identifier, identifier, ... ;
…dann müssten Arrays logischerweise so deklariert werden:
int[10] a;
was in Ordnung ist, aber nicht widerspiegelt, wie Sie verwendena. Beachten Sie, dass dies auch für Funktionen gilt – wir deklarieren Funktionen wie folgt:
void foo(int a, char *b);
statt
void(int a, char* b) foo;
Im Allgemeinen bedeutet die Regel „Deklaration von Spiegeln verwenden“, dass Sie sich nur einen Satz von Assoziativitätsregeln merken müssen, die für beide Operatoren wie gelten *, [] und () wenn Sie den Wert verwenden, und die entsprechenden Token in Deklaratoren wie *, [] und ().
Nach einigem Nachdenken denke ich, dass es sich auch lohnt, auf die Schreibweise “Zeiger auf int” wie “int*” ist sowieso nur eine Folge von “declaration mirrors use”. Wenn Sie einen anderen Deklarationsstil verwenden würden, wäre es wahrscheinlich sinnvoller, “”Zeiger auf int” wie “&int“, oder etwas ganz anderes wie “@int“.
Hmm, das klingt für mich nicht nach einem sehr guten Grund. ich tun möchten Arrays als deklarieren int[10], so machen es Java und C#. Gibt es andere Beispiele in der C-Syntax für die Verwendung der Deklarationsspiegelung?
– EMP
15. Juli 2010 um 23:44 Uhr
@Evgeny, C ist eine ganz andere Sprache als Java. Ein Java-Array ist völlig anders. Die Array-Variable enthält nur eine änderbare Referenz auf ein Array. AC-Array-Variable ist das Array. Ein weiteres Beispiel für die “Verwendung von Deklarationsspiegeln” ist die Deklaration einer Funktion, die einen Zeiger auf eine ganze Zahl zurückgibt. int *foo(int bar);. Dies spiegelt die Tatsache wider, dass *foo(3) ist ein int. Ich schlage vor, Sie lesen K&R C 2nd ed., wo dies erklärt wird.
– Matthäus Flaschen
15. Juli 2010 um 23:55 Uhr
@Evgeny: Das offensichtlichste andere Beispiel sind Funktionsdeklarationen, die so geschrieben sind, dass sie wie der Funktionsaufruf aussehen.
– Café
16. Juli 2010 um 0:11 Uhr
Umhang1232
Es gibt eine Webseite auf Die Entwicklung der C-Sprache das besagt: “Die Syntax dieser Deklarationen spiegelt die Beobachtung wider, dass i, *pi und **ppi alle einen int-Typ ergeben, wenn sie in einem Ausdruck verwendet werden.” Suchen Sie auf der Seite nach diesem Satz, um den entsprechenden Abschnitt zu finden, in dem diese Frage behandelt wird.
erukiform
Es mag einen zusätzlichen historischen Grund geben, aber ich habe es immer so verstanden:
Eine Deklaration, ein Typ.
Wenn a, b, c und d hier vom gleichen Typ sein müssen:
int a, b, c, d;
Dann muss auch alles in der Zeile eine Ganzzahl sein.
int a, *b, **c, ***d;
Die 4 ganzen Zahlen:
a
*b
**c
***d
Es kann auch mit der Operatorpriorität zusammenhängen oder es kann zu einem bestimmten Zeitpunkt in der Vergangenheit gewesen sein.
Die Frage war nicht, wie Sie es verstanden haben.
– Georg Fritzsche
15. Juli 2010 um 23:25 Uhr
@georg: Es ist nur eine andere Formulierung der beiden oben genannten. wie hast du es verstanden?
– kegelförmig
15. Juli 2010 um 23:34 Uhr
@Georg, eruciform ist richtig. Aus K&R C, „Die Deklaration des Zeigers ip, int *ip, ist als Gedächtnisstütze gedacht; es sagt, dass der Ausdruck *ip ist ein int. Die Syntax der Deklaration einer Variablen ahmt die Syntax von Ausdrücken nach, in denen die Variable erscheinen könnte. Dies ist der Grund für die Syntax.
– Matthäus Flaschen
15. Juli 2010 um 23:47 Uhr
eruciform, @matthew, die Frage stellt zB “warum wird es so geparst”, dh warum wurde die Sprache so gestaltet. Ich sehe nur “So verstehe ich die Syntax” in dieser antwort 🙂
– Georg Fritzsche
15. Juli 2010 um 23:54 Uhr
@Georg, er sagte nie “So verstehe ich die Syntax” Das Verständnis, das er für das Design der Sprache gab ist der wahre Grund für das Design der Sprache.
– Matthäus Flaschen
16. Juli 2010 um 0:00 Uhr
Ich nehme an, es hängt mit der vollständigen Deklarationssyntax für Typmodifikatoren zusammen:
int x[20], y;
int (*fp)(), z;
In diesen Beispielen scheint es viel offensichtlicher, dass die Modifikatoren nur eine der Deklarationen betreffen. Eine Vermutung ist, dass sich K&R nach der Entscheidung, Modifikatoren auf diese Weise zu entwerfen, als “richtig” anfühlte, dass Modifikatoren nur eine Deklaration betreffen.
Nebenbei bemerkt würde ich empfehlen, sich nur auf eine Variable pro Deklaration zu beschränken:
int *x;
int y;
bta
Das * ändert den Variablennamen, nicht den Typbezeichner. Das liegt vor allem an der Art und Weise * wird geparst. Nehmen Sie diese Aussagen:
char* x;
char *x;
Diese Aussagen sind gleichwertig. Das * Der Operator muss zwischen dem Typbezeichner und dem Variablennamen stehen (er wird wie ein Infix-Operator behandelt), kann aber auf beiden Seiten des Leerzeichens stehen. In Anbetracht dessen die Erklärung
int* a, b;
würde nicht machen b ein Zeiger, denn es gibt keinen * daneben. Das * wirkt nur auf die Objekte auf beiden Seiten davon.
Denken Sie auch so darüber nach: wenn Sie die Erklärung schreiben int x;darauf deuten Sie hin x ist eine ganze Zahl. Wenn y ist dann ein Zeiger auf eine ganze Zahl *y ist eine ganze Zahl. Wenn du schreibst int *y;darauf deuten Sie hin *y ist eine Ganzzahl (was Sie wollen). In der Aussage char a, *b, ***c;geben Sie an, dass die Variable ader dereferenzierte Wert von bund den dreifach dereferenzierten Wert von c sind alle typ char. Das Deklarieren von Variablen auf diese Weise macht die Verwendung des Sternoperators (fast) konsistent mit der Dereferenzierung.
Ich stimme zu, dass es fast sinnvoller wäre, wenn es umgekehrt wäre. Um diese Falle zu vermeiden, habe ich mir zur Regel gemacht, Zeiger auf einer Linie immer für sich zu deklarieren.
Das ist der Status quo, aber warum ist es so?
– Georg Fritzsche
15. Juli 2010 um 23:23 Uhr
Betrachten Sie die Deklaration:
int *a[10];
int (*b)[10];
Das erste ist ein Array von zehn Zeigern auf ganze Zahlen, das zweite ist ein Zeiger auf ein Array von zehn ganzen Zahlen.
Wenn nun der * an die Typdeklaration angehängt wäre, wäre es syntaktisch nicht gültig, eine Klammer dazwischen zu setzen. Sie müssten also einen anderen Weg finden, um zwischen den beiden Formen zu unterscheiden.
Das ist der Status quo, aber warum ist es so?
– Georg Fritzsche
15. Juli 2010 um 23:23 Uhr
Lorenz
Denn wenn die Aussage
int* a, b;
zu erklären waren b als Zeiger auch, dann hättest du keine Möglichkeit zu deklarieren
int* a;
int b;
auf einer einzigen Zeile.
Andererseits kann man das
int*a, *b;
um zu bekommen, was du willst.
Stellen Sie sich das so vor: So wie es jetzt ist, ist es immer noch die prägnanteste und doch einzigartige Art, es zu tun. Darum geht es in C hauptsächlich 🙂
Ja, nun, ebenso können Sie ein Int und ein Float nicht in derselben Zeile deklarieren – na und? Eigentlich kann man sie nicht gleich behandeln Aussageaber du könntest eine haben Linie das gesagt int* a; int b; – Kein Problem.
– EMP
15. Juli 2010 um 23:46 Uhr
13441600cookie-checkZeigersyntax in C: Warum gilt * nur für die erste Variable?yes
Um ehrlich zu sein, wenn die C-Sprache das gemacht hat
*
Ändern Sie den Typ, dann würden die Leute fragen: “Warum nichtint *a, b;
Gib mir einen Zeiger und eine Ganzzahl?”.– bta
15. Juli 2010 um 23:46 Uhr
@bta, ja, würden wir – aber ich denke, es hätte weniger Leute verwirrt. Jedenfalls geht es nicht darum, über die Entscheidung zu streiten, die vor 40 Jahren getroffen wurde, sondern nur darum, zu verstehen, ob es Gründe dafür gibt, die mir nicht bekannt sind.
– EMP
16. Juli 2010 um 0:11 Uhr
Vielleicht möchten Sie dies lesen c-faq.com/decl/charstarws.html
– Amarghosch
16. Juli 2010 um 6:34 Uhr