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.

    – 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

Benutzer-Avatar
Café

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 verwenden a. 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

Benutzer-Avatar
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.

Benutzer-Avatar
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:

  1. a
  2. *b
  3. **c
  4. ***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;

Benutzer-Avatar
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

Benutzer-Avatar
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

1344160cookie-checkZeigersyntax in C: Warum gilt * nur für die erste Variable?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy