Warum steht das Sternchen vor dem Variablennamen und nicht nach dem Typ?

187

Warum benennen die meisten C-Programmierer Variablen wie folgt:

int *myVariable;

anstatt so:

int* myVariable;

Beide sind gültig. Es scheint mir, dass das Sternchen ein Teil des Typs ist, nicht ein Teil des Variablennamens. Kann jemand diese Logik erklären?

WBlasko
quelle
1
Der zweite Stil scheint im Allgemeinen intuitiver zu sein, aber der erstere ist der richtige Weg, um typbezogene Fehler im Code zu vermeiden. Wenn Sie wirklich an den letzteren Stil gebunden sind, können Sie immer mitmachen typedefs, aber das wird meiner Meinung nach unnötige Komplexität hinzufügen.
Wolke

Antworten:

250

Sie sind genau gleichwertig. In

int *myVariable, myVariable2;

Es scheint offensichtlich, dass myVariable den Typ int * hat , während myVariable2 den Typ int hat . Im

int* myVariable, myVariable2;

es mag offensichtlich erscheinen, dass beide vom Typ int * sind , aber das ist nicht korrekt, wie myVariable2der Typ int .

Daher ist der erste Programmierstil intuitiver.

luiscubal
quelle
135
Vielleicht, aber ich würde Typen nicht in einer Deklaration mischen und abgleichen.
BobbyShaftoe
15
@ BobbyShaftoe Einverstanden. Selbst nachdem ich alle Argumente hier gelesen habe, bleibe ich bei int* someVarpersönlichen Projekten. Es macht mehr Sinn.
Alyssa Haroldsen
30
@Kupiakos Es ist nur sinnvoller, bis Sie die Deklarationssyntax von C lernen, die auf "Deklarationen folgen der Verwendung" basiert. Deklarationen verwenden genau dieselbe Syntax wie Variablen mit demselben Typ. Wenn Sie ein Array von Ints deklarieren, sieht es nicht so aus : int[10] x. Dies ist einfach nicht die Syntax von C. Die Grammatik analysiert explizit als: int (*x)und nicht als (int *) x, daher ist das Platzieren des Sterns auf der linken Seite einfach irreführend und basiert auf einem Missverständnis der C-Deklarationssyntax.
Peaker
8
Korrektur: Daher sollten Sie niemals mehr als eine Variable in einer einzelnen Zeile deklarieren. Im Allgemeinen sollten Sie einen bestimmten Codierungsstil nicht motivieren, der auf einem anderen nicht verwandten, schlechten und gefährlichen Codierungsstil basiert.
Lundin
6
Deshalb halte ich mich an eine Variable pro Zeigerdeklaration. Es gibt absolut keine Verwirrung, wenn Sie int* myVariable; int myVariable2;stattdessen tun .
Patrick Roberts
122

Wenn Sie es anders betrachten, *myVariableist es von Typ int, was Sinn macht.

Biozink
quelle
6
Dies ist meine Lieblingserklärung und funktioniert gut, weil sie die Deklarationsmerkmale von C im Allgemeinen erklärt - sogar die ekelhafte und knorrige Funktionszeigersyntax.
Benjamin Pollack
12
Es ist irgendwie ordentlich, da Sie sich vorstellen können, dass es keine tatsächlichen Zeigertypen gibt. Es gibt nur Variablen, die bei entsprechender Referenzierung oder Dereferenzierung einen der primitiven Typen ergeben.
Biozink
1
Tatsächlich kann '* myVariable' vom Typ NULL sein. Um die Sache noch schlimmer zu machen, könnte es sich nur um einen zufälligen Speicherplatz handeln.
Qonf
4
qonf: NULL ist kein Typ. myVariablekann NULL sein. In diesem Fall *myVariablewird ein Segmentierungsfehler verursacht, es gibt jedoch keinen Typ NULL.
Daniel Roethlisberger
28
Dieser Punkt kann in einem solchen Kontext irreführend sein: int x = 5; int *pointer = &x;weil er darauf hindeutet, dass wir das int *pointerauf einen bestimmten Wert setzen, nicht auf das pointerselbst.
Rafalcieslak
40

Weil das * in dieser Zeile enger an die Variable als an den Typ gebunden ist:

int* varA, varB; // This is misleading

Wie @Lundin weiter unten ausführt, fügt const noch mehr Feinheiten hinzu, über die man nachdenken muss. Sie können dies vollständig umgehen, indem Sie eine Variable pro Zeile deklarieren, was niemals mehrdeutig ist:

int* varA;
int varB;

Das Gleichgewicht zwischen klarem Code und prägnantem Code ist schwer zu finden - ein Dutzend redundanter Zeilen von int a;ist auch nicht gut. Trotzdem verwende ich standardmäßig eine Deklaration pro Zeile und mache mir Sorgen, dass der Code später kombiniert wird.

ojrac
quelle
2
Nun, das irreführende erste Beispiel ist in meinen Augen ein Designfehler. Wenn ich könnte, würde ich diese Art der Deklaration vollständig aus C entfernen und sie so gestalten, dass beide vom Typ int * sind.
Adam Bajger
1
"Das * bindet enger an die Variable als an den Typ" Dies ist ein naives Argument. Überlegen Sie int *const a, b;. Wo bindet das *? Der Typ von aist int* const, wie können Sie also sagen, dass das * zur Variablen gehört, wenn es Teil des Typs selbst ist?
Lundin
1
Spezifisch für die Frage oder für alle Fälle: Wählen Sie einen aus. Ich werde eine Notiz machen, aber dies ist ein weiteres gutes Argument für meinen letzten Vorschlag: Eine Erklärung pro Zeile verringert die Möglichkeiten, dies durcheinander zu bringen.
Ojrac
36

Bisher hat hier niemand erwähnt, dass dieses Sternchen tatsächlich der " Dereferenzierungsoperator " in C ist.

*a = 10;

Die Zeile oben bedeutet nicht , ich zuweisen möchten 10zu a, bedeutet dies , ich zugewiesen werden soll 10, was auch immer Speicherplatz aauf Punkte an . Und ich habe noch nie jemanden schreiben sehen

* a = 10;

hast du? Der Dereferenzierungsoperator wird also so gut wie immer ohne Leerzeichen geschrieben. Dies ist wahrscheinlich, um es von einer Multiplikation zu unterscheiden, die über mehrere Zeilen verteilt ist:

x = a * b * c * d
  * e * f * g;

Hier *ewäre irreführend, nicht wahr?

Okay, was bedeutet nun die folgende Zeile eigentlich:

int *a;

Die meisten Leute würden sagen:

Dies bedeutet, dass dies aein Zeiger auf einen intWert ist.

Dies ist technisch korrekt, die meisten Leute sehen / lesen es gerne so und so würden es moderne C-Standards definieren (beachten Sie, dass Sprache C selbst älter ist als alle ANSI- und ISO-Standards). Aber es ist nicht die einzige Möglichkeit, es zu betrachten. Sie können diese Zeile auch wie folgt lesen:

Der dereferenzierte Wert von aist vom Typ int.

Tatsächlich kann das Sternchen in dieser Deklaration auch als Dereferenzierungsoperator angesehen werden, was auch seine Platzierung erklärt. Und das aist ein Zeiger, der überhaupt nicht wirklich deklariert ist. Dies impliziert, dass das einzige, was Sie tatsächlich dereferenzieren können, ein Zeiger ist.

Der C-Standard definiert für den *Bediener nur zwei Bedeutungen :

  • Indirektionsoperator
  • Multiplikationsoperator

Und Indirektion ist nur eine einzige Bedeutung, es gibt keine zusätzliche Bedeutung für das Deklarieren eines Zeigers, es gibt nur Indirektion, was die Dereferenzierungsoperation tut, sie führt einen indirekten Zugriff durch, also ist auch innerhalb einer Anweisung wie int *a;dieser ein indirekter Zugriff ( *Mittel) indirekter Zugang) und damit ist die zweite Aussage viel näher am Standard als die erste.

Mecki
quelle
6
Vielen Dank, dass Sie mich davor bewahrt haben, hier eine weitere Antwort zu schreiben. Übrigens lese ich normalerweise int a, *b, (*c)();so etwas wie "deklariere die folgenden Objekte als int: das Objekt a, das Objekt, auf das von gezeigt wird b, und das Objekt, das von der Funktion zurückgegeben wird, auf die von gezeigt wird c".
Antti Haapala
1
Das *in int *a;ist kein Operator und es ist keine Dereferenzierung a(die noch nicht einmal definiert ist)
MM
1
@MM Bitte benennen Sie die Seiten- und Zeilennummer eines ISO C-Standards, in dem dieser Standard besagt, dass ein Sternchen etwas anderes als Multiplikation oder Indirektion sein kann. Es zeigt nur "Zeigerdeklaration" als Beispiel, es definiert nirgends eine dritte Bedeutung für ein Sternchen (und es definiert keine Bedeutung, die kein Operator wäre). Oh, und ich habe nirgends behauptet, irgendetwas sei "definiert", das hast du erfunden. Oder wie Jonathan Leffler es ausdrückte: Im C-Standard ist * immer "Grammatik", es ist nicht Teil der aufgeführten Deklarationsspezifizierer (es ist also nicht Teil einer Deklaration, also muss es ein Operator sein)
Mecki
1
@MM 6.7.6.1 zeigt die Deklaration nur anhand eines Beispiels, genau wie ich sagte, es gibt keine Bedeutung für *(es gibt nur eine Bedeutung für den Gesamtausdruck, nicht für das *innerhalb des Ausdrucks!). Es heißt, dass "int a;" deklariert einen Zeiger, was er tut, behauptet nie etwas anderes, aber ohne eine Bedeutung, die ihm gegeben *wird. Das Lesen als * der dereferenzierte Wert von aist ein int ist immer noch völlig gültig, da dies dieselbe sachliche Bedeutung hat. Nichts, wirklich nichts, was in 6.7.6.1 geschrieben wurde, würde dieser Aussage widersprechen.
Mecki
2
Es gibt keinen "Gesamtausdruck". int *a;ist eine Erklärung, kein Ausdruck. awird nicht dereferenziert von int *a;. aexistiert noch nicht einmal zum Zeitpunkt der *Verarbeitung. Denken Sie, dass dies int *a = NULL;ein Fehler ist, weil er einen Nullzeiger dereferenziert?
MM
17

Ich werde hier auf die Nerven gehen und sagen, dass es eine klare Antwort auf diese Frage gibt , sowohl für Variablendeklarationen als auch für Parameter- und Rückgabetypen, dh , das Sternchen sollte neben dem Namen stehen : int *myVariable;. Um zu verstehen, warum, sehen Sie sich an, wie Sie andere Symboltypen in C deklarieren:

int my_function(int arg); für eine Funktion;

float my_array[3] für ein Array.

Das allgemeine Muster, das als Deklaration nach Verwendung bezeichnet wird , besteht darin, dass der Typ eines Symbols in den Teil vor dem Namen und die Teile um den Namen aufgeteilt wird und diese Teile um den Namen die Syntax nachahmen, die Sie zum Abrufen von a verwenden würden Wert des Typs links:

int a_return_value = my_function(729);

float an_element = my_array[2];

und : int copy_of_value = *myVariable;.

C ++ wirft einen Schlüssel in die Arbeit mit Referenzen, da die Syntax an der Stelle, an der Sie Referenzen verwenden, mit der von Werttypen identisch ist. Sie könnten also argumentieren, dass C ++ einen anderen Ansatz für C verfolgt. Andererseits behält C ++ dieselbe bei Verhalten von C im Fall von Zeigern, daher sind Referenzen in dieser Hinsicht wirklich ungerade.

Injektilo
quelle
12

Das ist nur eine Frage der Präferenz.

Wenn Sie den Code lesen, ist die Unterscheidung zwischen Variablen und Zeigern im zweiten Fall einfacher. Dies kann jedoch zu Verwirrung führen, wenn Sie sowohl Variablen als auch Zeiger eines gemeinsamen Typs in eine einzelne Zeile setzen (was von Projektrichtlinien häufig nicht empfohlen wird.) weil die Lesbarkeit abnimmt).

Ich ziehe es vor, Zeiger mit dem entsprechenden Vorzeichen neben dem Typnamen zu deklarieren, z

int* pMyPointer;
Macbirdie
quelle
3
Die Frage bezieht sich auf C, wo es keine Referenzen gibt.
Antti Haapala
Vielen Dank, dass Sie darauf hingewiesen haben, obwohl es bei der Frage nicht um Zeiger oder Verweise ging, sondern im Grunde genommen um die Code-Formatierung.
Macbirdie
8

Ein großer Guru sagte einmal: "Lies es wie der Compiler, du musst."

http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835

Zugegeben, dies war das Thema Const Placement, aber hier gilt die gleiche Regel.

Der Compiler liest es wie folgt:

int (*a);

nicht so wie:

(int*) a;

Wenn Sie es sich zur Gewohnheit machen, den Stern neben der Variablen zu platzieren, werden Ihre Deklarationen leichter lesbar. Es vermeidet auch Schandflecken wie:

int* a[10];

- Bearbeiten -

Um zu erklären , genau das, was ich meine , wenn ich sage , es als geparst int (*a), das bedeutet , dass *bindet stärker an , aals es zu int, in sehr die Art und Weise , dass in dem Ausdruck 4 + 3 * 7 3bindet stärker an , 7als es zu 4dem höheren Vorrang fälligen *.

Mit Entschuldigungen für die ASCII-Kunst int *asieht eine Zusammenfassung des AST für das Parsen ungefähr so ​​aus:

      Declaration
      /         \
     /           \
Declaration-      Init-
Secifiers       Declarator-
    |             List
    |               |
    |              ...
  "int"             |
                Declarator
                /       \
               /        ...
           Pointer        \
              |        Identifier
              |            |
             "*"           |
                          "a"

Wie deutlich gezeigt wird, *bindet es enger an aden gemeinsamen Vorfahren Declarator, während Sie den ganzen Weg den Baum hinaufgehen müssen Declaration, um einen gemeinsamen Vorfahren zu finden, an dem der beteiligt ist int.

dgnuff
quelle
Nein, der Compiler liest den Typ definitiv als (int*) a.
Lundin
@Lundin Dies ist das große Missverständnis, das die meisten modernen C ++ - Programmierer haben. Das Parsen einer Variablendeklaration geht ungefähr so. Schritt 1. Lesen Sie das erste Token, das zum "Basistyp" der Deklaration wird. intin diesem Fall. Schritt 2. Lesen Sie eine Erklärung, einschließlich aller Arten von Dekorationen. *ain diesem Fall. Schritt 3 Lesen Sie das nächste Zeichen. Wenn Komma, verbrauchen Sie es und fahren Sie mit Schritt 2 fort. Wenn das Semikolon stoppt. Wenn irgendetwas anderes einen Syntaxfehler auslöst. ...
dgnuff
@Lundin ... Wenn der Parser es so liest, wie Sie es vorschlagen, können wir schreiben int* a, b;und ein Paar Zeiger erhalten. Der Punkt, den ich mache, ist, dass das *an die Variable bindet und mit ihr analysiert wird, nicht mit dem Typ, der den "Basistyp" der Deklaration bildet. Dies ist auch ein Grund dafür, dass typedefs eingeführt wurden, um typedef int *iptr; iptr a, b;einige Zeiger erstellen zu können. Durch eine typedef Sie können die Bindung *an die int.
Dgnuff
1
... Natürlich "kombiniert" der Compiler den Basistyp aus dem Declaration-Specifiermit den "Dekorationen" in der Declarator, um den endgültigen Typ für jede Variable zu erhalten. Allerdings spielt es keine „Bewegung“ , die Dekorationen auf die Erklärung Spezifizierer sonst int a[10], b;würde produzieren völlig lächerlich Ergebnisse, Es analysiert , int *a, b[10];wie int *a , b[10] ;. Es gibt keine andere Möglichkeit, es sinnvoll zu beschreiben.
dgnuff
1
Ja gut, der wichtige Teil hier ist nicht wirklich die Syntax oder Reihenfolge der Compiler-Analyse, sondern dass der Typ int*aam Ende vom Compiler als " ahas type int*" gelesen wird . Das meine ich mit meinem ursprünglichen Kommentar.
Lundin
3

Weil es sinnvoller ist, wenn Sie Erklärungen haben wie:

int *a, *b;
Greg Rogers
quelle
5
Dies ist buchstäblich ein Beispiel dafür, wie man die Frage stellt. Nein, so macht es keinen Sinn. "int * a, b" könnte genauso gut beide Zeiger machen.
MichaelGG
1
@MichaelGG Du hast den Schwanz, der den Hund dort wedelt. Sicher K & R konnte angegeben haben , dass int* a, b;aus beinem Zeiger auf int. Aber sie haben es nicht getan. Und das aus gutem Grund. Was ist unter Ihrem vorgeschlagenen System die Art bder folgenden Erklärung : int* a[10], b;?
dgnuff
2

Um mehrere Zeiger in einer Zeile zu deklarieren, bevorzuge ich, int* a, * b;dass "a" intuitiver als Zeiger auf eine Ganzzahl deklariert wird und Stile nicht gemischt werden, wenn ebenfalls "b" deklariert wird. Wie jemand sagte, würde ich sowieso nicht zwei verschiedene Typen in derselben Aussage deklarieren.

Heyitsluke
quelle
2

Leute, die es vorziehen, int* x;versuchen, ihren Code in eine fiktive Welt zu zwingen, in der der Typ links und die Kennung (Name) rechts ist.

Ich sage "fiktiv", weil:

In C und C ++ ist der deklarierte Bezeichner im allgemeinen Fall von den Typinformationen umgeben.

Das mag verrückt klingen, aber Sie wissen, dass es wahr ist. Hier sind einige Beispiele:

  • int main(int argc, char *argv[])bedeutet " mainist eine Funktion, die ein intund ein Array von Zeigern auf charein nimmt und ein zurückgibt int." Mit anderen Worten, die meisten Typinformationen befinden sich rechts. Einige Leute denken, dass Funktionsdeklarationen nicht zählen, weil sie irgendwie "besonders" sind. OK, versuchen wir es mit einer Variablen.

  • void (*fn)(int)means fnist ein Zeiger auf eine Funktion, die ein nimmt intund nichts zurückgibt.

  • int a[10]deklariert 'a' als Array von 10 ints.

  • pixel bitmap[height][width].

  • Klar, ich habe Beispiele ausgewählt, die rechts viele Typinformationen enthalten, um meinen Standpunkt zu verdeutlichen. Es gibt viele Deklarationen, bei denen die meisten - wenn nicht alle - des Typs links stehen, wie z struct { int x; int y; } center.

Diese Deklarationssyntax entstand aus dem Wunsch von K & R, dass Deklarationen die Verwendung widerspiegeln. Das Lesen einfacher Deklarationen ist intuitiv und das Lesen komplexerer Deklarationen kann durch Erlernen der Rechts-Links-Rechts-Regel (manchmal auch als Spiralregel oder nur als Rechts-Links-Regel bezeichnet) beherrscht werden.

C ist einfach genug, dass viele C-Programmierer diesen Stil annehmen und einfache Deklarationen schreiben als int *p.

In C ++ wurde die Syntax etwas komplexer (mit Klassen, Referenzen, Vorlagen, Aufzählungsklassen), und als Reaktion auf diese Komplexität werden Sie in vielen Deklarationen mehr Aufwand beim Trennen des Typs vom Bezeichner sehen. Mit anderen Worten, int* pwenn Sie einen großen Teil des C ++ - Codes auschecken , werden möglicherweise mehr Deklarationen im Stil angezeigt.

In beiden Sprachen, Sie können immer den Typen haben auf der linken Seite der variablen Erklärungen (1) nie mehrere Variablen in derselben Anweisung, und (2) die Nutzung von erklärt typedefs (oder Alias - Deklarationen, die ironischerweise den Alias setzen Bezeichner links von den Typen). Beispielsweise:

typedef int array_of_10_ints[10];
array_of_10_ints a;
Adrian McCarthy
quelle
Kleine Frage, warum kann nicht void (* fn) (int) bedeuten "fn ist eine Funktion, die ein int akzeptiert und zurückgibt (void *)?
Soham Dongargaonkar
1
@ a3y3: Da die Klammern in (*fn)den Zeiger beibehalten fnund nicht den Rückgabetyp.
Adrian McCarthy
Verstanden. Ich denke, es ist wichtig genug, um in Ihre Antwort aufgenommen zu werden. Ich werde bald eine Bearbeitung vorschlagen.
Soham Dongargaonkar
1
Ich denke, das macht die Antwort unübersichtlich, ohne viel Wert hinzuzufügen. Dies ist einfach die Syntax der Sprache. Die meisten Leute, die sich fragen, warum die Syntax so ist, kennen die Regeln wahrscheinlich bereits. Jeder andere, der in diesem Punkt verwirrt ist, kann die Klarstellung in diesen Kommentaren sehen.
Adrian McCarthy
1

Ich habe bereits auf eine ähnliche Frage in CP geantwortet, und da dies niemand erwähnt hat, muss ich auch hier darauf hinweisen, dass C eine freie Formatsprache ist , unabhängig davon, welchen Stil Sie wählen, ist es in Ordnung, während der Parser jedes Token unterscheiden kann. Diese Besonderheit von C führte zu einer ganz besonderen Art von Wettbewerb, der als C-Verschleierungswettbewerb bezeichnet wird .

Frankie_C
quelle
1

Viele der Argumente in diesem Thema sind einfach subjektiv und das Argument über "Der Stern bindet an den Variablennamen" ist naiv. Hier sind einige Argumente, die nicht nur Meinungen sind:


Die vergessenen Zeigertyp-Qualifizierer

Formal gehört der "Stern" weder zum Typ noch zum Variablennamen, er ist Teil eines eigenen grammatikalischen Elements namens Zeiger . Die formale C-Syntax (ISO 9899: 2018) lautet:

(6.7) Deklaration:
Deklarationsspezifizierer Init-Deklarator-Liste opt ;

Wobei Deklarationsspezifizierer den Typ (und den Speicher) enthalten und die Init-Deklaratorliste den Zeiger und den Variablennamen enthält. Was wir sehen, wenn wir diese Deklaratorlistensyntax weiter analysieren:

(6.7.6) Deklarator:
Zeiger Opt - Direktdeklarator
...
(6.7.6) Zeiger:
* Typ-Qualifizierer-Liste Opt
* Typ-Qualifizierer-Liste Opt- Zeiger

Wenn ein Deklarator die gesamte Deklaration ist, ist ein Direktdeklarator der Bezeichner (Variablenname), und ein Zeiger ist der Stern, gefolgt von einer optionalen Typqualifizierungsliste, die zum Zeiger selbst gehört.

Was die verschiedenen Stilargumente zu "Der Stern gehört zur Variablen" inkonsistent macht, ist, dass sie diese Zeigertypqualifizierer vergessen haben. int* const x, int *const xOder int*const x?

Überlegen Sie int *const a, b;, welche Arten von aund b? Nicht so offensichtlich, dass "der Stern zur Variablen gehört". Vielmehr würde man anfangen zu überlegen, wo das hingehört const.

Sie können definitiv ein stichhaltiges Argument dafür vorbringen, dass der Stern zum Qualifikator für den Zeigertyp gehört, aber nicht viel darüber hinaus.

Die Typqualifizierungsliste für den Zeiger kann Probleme für diejenigen verursachen, die den int *aStil verwenden. Diejenigen, die Zeiger in einem verwenden typedef(was wir nicht sollten, sehr schlechte Praxis!) Und denken, "der Stern gehört zum Variablennamen", neigen dazu, diesen sehr subtilen Fehler zu schreiben:

    /*** bad code, don't do this ***/
    typedef int *bad_idea_t; 
    ...
    void func (const bad_idea_t *foo);

Dies kompiliert sauber. Jetzt könnten Sie denken, dass der Code const korrekt gemacht wurde. Nicht so! Dieser Code ist aus Versehen eine gefälschte Konstantenkorrektheit.

Die Art von fooist tatsächlich int*const*- der äußerste Zeiger wurde schreibgeschützt gemacht, nicht der auf Daten gerichtete. Innerhalb dieser Funktion können wir also **foo = n;den Variablenwert im Aufrufer ändern.

Dies liegt daran, dass im Ausdruck const bad_idea_t *foodas *hier nicht zum Variablennamen gehört! Im Pseudocode ist diese Parameterdeklaration als const (bad_idea_t *) foound nicht als zu lesen (const bad_idea_t) *foo. Der Stern gehört in diesem Fall zum versteckten Zeigertyp - der Typ ist ein Zeiger und ein const-qualifizierter Zeiger wird als geschrieben *const.

Aber dann liegt die Wurzel des Problems im obigen Beispiel in der Praxis, Zeiger hinter a typedefund nicht hinter dem *Stil zu verstecken .


In Bezug auf die Deklaration mehrerer Variablen in einer einzelnen Zeile

Das Deklarieren mehrerer Variablen in einer einzelnen Zeile wird allgemein als schlechte Praxis anerkannt 1) . CERT-C fasst es gut zusammen als:

DCL04-C. Deklarieren Sie nicht mehr als eine Variable pro Deklaration

Nur die englische lesen, dann den gesunden Menschenverstand stimmt zu, dass eine Erklärung sein sollte , eine Erklärung.

Und es spielt keine Rolle, ob die Variablen Zeiger sind oder nicht. Wenn Sie jede Variable in einer einzelnen Zeile deklarieren, wird der Code in fast allen Fällen klarer.

Das Argument, dass der Programmierer verwirrt int* a, bist, ist also schlecht. Die Wurzel des Problems ist die Verwendung mehrerer Deklaratoren, nicht die Platzierung der *. Unabhängig vom Stil sollten Sie stattdessen Folgendes schreiben:

    int* a; // or int *a
    int b;

Ein anderes stichhaltiges, aber subjektives Argument wäre, dass der gegebene int* aTyp aohne Frage ist int*und der Stern daher zum Typqualifizierer gehört.

Aber im Grunde ist meine Schlussfolgerung, dass viele der hier veröffentlichten Argumente nur subjektiv und naiv sind. Sie können für keinen der beiden Stile wirklich ein gültiges Argument vorbringen - es ist wirklich eine Frage der subjektiven persönlichen Präferenz.


1) CERT-C DCL04-C .

Lundin
quelle
Eher amüsant, wenn Sie diesen Artikel lesen, den ich verlinkt habe, gibt es einen kurzen Abschnitt zum Thema typedef int *bad_idea_t; void func(const bad_idea_t bar); Wie der große Prophet Dan Saks lehrt: "Wenn Sie immer constso weit rechts wie möglich platzieren, ohne die semantische Bedeutung zu ändern", hört dies vollständig auf ein Problem sein. Es macht auch Ihre constErklärungen konsistenter zu lesen. "Alles rechts vom Wort const ist das, was const ist, alles links vom Typ ist sein Typ." Dies gilt für alle Konstanten in einer Deklaration. Versuchen Sie es mitint const * * const x;
dgnuff
-1

Erwägen

int *x = new int();

Dies bedeutet nicht

int *x;
*x = new int();

Es übersetzt tatsächlich zu

int *x;
x = new int();

Dies macht die int *xNotation etwas inkonsistent.

Urquhart
quelle
newist ein C ++ - Operator. Seine Frage ist mit "C" und nicht mit "C ++" gekennzeichnet.
Sapphire_Brick