In C *
wird der Indirektionsoperator oder der Dereferenzierungsoperator genannt. Ich verstehe, wie es funktioniert, wenn es in einer Anweisung verwendet wird. Es ist sinnvoll zu schreiben *p
oder * p
, wenn man bedenkt, dass es sich um einen unären Operator handelt.
Manchmal wird jedoch in einer Deklaration a *
verwendet.
void move(int *units) { ... }
oder
int *p = &x;
Es scheint mir seltsam, dass hier ein Operator verwendet wird. Sie können Dinge wie nicht tun
void move(int units++) { ... }
wo ++
ist auch ein unärer Operator. Ist dies *
auch der Indirektionsoperator oder hat dies *
eine andere Bedeutung, wenn er etwas über den Typ des Zeigers aussagt? (Wenn dies der Fall ist, erwäge ich, dies beispielsweise int* units
in Erklärungen und int x = *p;
aus Gründen der Klarheit zu verwenden.)
In dieser Antwort heißt es:
Der C-Standard definiert für den Operator * nur zwei Bedeutungen:
- Indirektionsoperator
- Multiplikationsoperator
Ich habe auch Leute gesehen, die behaupteten, dass das *
tatsächlich Teil des Typs ist. Das verwirrt mich.
void move(int *units) { ... }
ist es ein Indirektionsoperator. Als Teil des Typs betrachtet, kann es auch geschrieben werdenvoid move(int* units) { ... }
, obwohl ich den früheren Stil bevorzuge. Sie lesen beide als "int Zeiger". Siehe auch stackoverflow.com/a/8911253Antworten:
Die kleinsten Teile der Sprache C sind lexikalische Token , wie Schlüsselwörter (zB
int
,if
,break
), Bezeichner (zBmove
,units
) und andere.*
ist ein lexikalisches Element, das als Interpunktionszeichen bezeichnet wird (wie zum Beispiel{}()+
). Ein Interpunktionszeichen kann je nach Verwendung unterschiedliche Bedeutungen haben:Im C11-Standard wird Kapitel 6.5 über Ausdrücke
*
als unärer Operator (Abschnitt 6.5.3.2 für die Indirektion) und als multiplikativer Operator (Abschnitt 6.5.5) definiert, genau wie Sie es beschrieben haben. Wird*
aber nur als Operator gemäß den grammatikalischen Regeln interpretiert, die gültige Ausdrücke bilden.Es gibt aber auch ein Kapitel 6.2 über Konzepte, in dem erklärt wird, dass Zeiger auf einen Typ abgeleitete Typen sind. Der Abschnitt 6.7.6.1 über Zeigerdeklaratoren ist genauer:
Dies macht in der Tat
*
Teil eines abgeleiteten Typs (*
bedeutet dort "Zeiger", aber es braucht immer einen anderen Typ, um zu sagen, auf welche Art von Dingen es auf etwas zeigt).Bemerkung: Darin besteht kein Widerspruch. Sie verwenden das lexikalische Sprachelement jeden Tag so differenziert, wenn Sie Englisch sprechen: "ein Handle " bezeichnet etwas und " handhaben " bedeutet etwas zu tun, zwei völlig unterschiedliche grammatikalische Verwendungen desselben lexikalischen Elements.
quelle
In C wird die Indirektion in einer Deklaration besser als Teil der Variablen als als Teil des Typs gelesen. Wenn ich habe:
Diese Anweisung könnte folgendermaßen interpretiert werden: Deklarieren Sie eine Variable mit dem Namen
a
, die bei der Dereferenzierung vom Typ istint
.Dies ist wichtig, wenn mehrere Variablen gleichzeitig deklariert werden:
Beide Deklarationen sind äquivalent und in beiden
a
undb
nicht vom selben Typ -a
ist ein Zeiger auf ein int undb
ein int. Die Deklaration (2) sieht jedoch so aus, als ob der "Zeigertyp" Teil des Typs ist, wenn es sich tatsächlich um die Deklaration von handelt*a
.quelle
So fügen Sie den anderen richtigen Antworten hinzu:
Es ist nur ein Deklarationsausdruck, der mögliche Verwendungsausdrücke widerspiegelt. IIRC, ich denke, Kernigan oder Ritchie haben es ein Experiment genannt! Hier ist ein geringfügig unterstützender Text:
(Meine Betonung.)
http://codinghighway.com/2013/12/29/the-absolute-definitive-guide-to-decipher-c-declarations/
Also, ja, Sie haben Recht, dies sind in der Tat dieselben Operatoren, die auf Deklarationsausdrücke angewendet werden, obwohl, wie Sie beobachtet haben, nur einige der Operatoren sinnvoll sind (z. B. ++ nicht).
Ein solcher Stern ist in der Tat Teil des Typs der einzelnen deklarierten Variablen; Wie andere Poster angemerkt haben, kann es jedoch nicht (genauer gesagt nicht) auf andere Variablen übertragen werden, die gleichzeitig deklariert werden (dh in derselben Deklarationsanweisung) - jede Variable beginnt mit demselben Basistyp wie das (eventuelle) Ziel und erhält dann seine eigenen (Möglichkeit anzuwenden oder nicht) Zeiger-, Array- und Funktionsoperatoren, um seinen Typ zu vervollständigen.
Aus diesem Grund bevorzugen erfahrene Programmierer (1)
int *p;
gegenüberint* p;
(2) und deklarieren nur eine einzige Variable pro Deklaration, obwohl die Sprache mehr zulässt.Hinzu
int (*p);
kommt eine rechtliche Erklärung, dass diese Eltern einfach gruppiert sind und in diesem einfachen Fall nichts anderes tun alsint *p
. Dies ist dasselbe wie zu sagen, dass ein (nicht deklarativer) Ausdruck(i) >= (0)
dasselbe ist wiei >= 0
, wie Sie immer legal hinzufügen können()
.Ich erwähnen , dass als ein weiteres Beispiel, obwohl, warum Programmierer eine Form über die andere bevorzugen, so betrachten
int (*p);
vsint(* p);
. Vielleicht können Sie sehen, wie die Klammern, der Stern usw. auf die Variable und nicht auf den Basistyp zutreffen (dh indem Sie alle zulässigen Klammern hinzufügen).quelle
In dieser Funktionsdeklaration:
das
*
ist ein Teil des Typs, das heißtint*
. Es ist kein Operator. Deshalb würden viele Leute es schreiben als:quelle
Nur die
*
,[]
und()
Betreiber haben keine Bedeutung in Erklärungen (C ++ fügt hinzu&
, aber wir gehen nicht in das hier).In der Erklärung
Die
int
-ness vonp
wird vom Typbezeichner angegebenint
, während die Zeigerzahl vonp
vom Deklarator angegeben wird*p
.Der Typ von
p
ist "Zeiger aufint
"; Dieser Typ wird vollständig durch die Kombination des Typspezifizierersint
und des Deklarators angegeben*p
.In einer Deklaration führt der Deklarator den Namen der deklarierten Sache (
p
) zusammen mit zusätzlichen Typinformationen ein, die nicht vom Typspezifizierer angegeben werden ("Zeiger auf"):Dies ist wichtig - Zeiger, Array und Funktion werden als Teil des Deklarators angegeben, nicht als Typspezifizierer 1 . Wenn du schreibst
es wird analysiert als
so
a
wird nur als Zeiger auf deklariertint
;b
undc
werden als reguläreint
s deklariert .Die
*
,[]
und()
Betreiber können kombiniert werden , um beliebig komplexe Typen zu erstellen:Beachten Sie, dass
*
,[]
und()
befolgen Sie in Deklarationen dieselben Vorrangregeln wie in Ausdrücken.*a[N]
wird wie*(a[N])
in Deklarationen und Ausdrücken analysiert .Das wirklich Wichtige dabei ist, dass die Form einer Deklaration mit der Form des Ausdrucks im Code übereinstimmt. Zurück zu unserem ursprünglichen Beispiel haben wir einen Zeiger auf eine Ganzzahl namens
p
. Wenn wir diesen ganzzahligen Wert abrufen möchten, verwenden wir den*
Operator zum Dereferenzierenp
wie folgt :Der Typ des Ausdrucks
*p
istint
, der sich aus der Deklaration ergibtWenn wir ein Array von Zeigern auf haben
double
und einen bestimmten Wert abrufen möchten, indizieren wir das Array und dereferenzieren das Ergebnis:Auch die Art des Ausdrucks
*ap[i]
istdouble
, der aus der Erklärung folgtWarum also nicht
++
eine Rolle spielen , in einer Erklärung , wie*
,[]
oder()
? Oder irgendein anderer Betreiber wie+
oder->
oder&&
?Nun, im Grunde, weil die Sprachdefinition dies sagt. Er setzt nur beiseite
*
,[]
und()
jede Rolle in einer Erklärung zu spielen, da Sie angeben , Zeiger, Array in der Lage sein müssen, und Funktionstypen. Es gibt keinen separaten "Inkrement-this" -Typ, sodass Sie nicht++
Teil einer Deklaration sein müssen. Es gibt keine „bitweise diese“ Art, so dass keine Notwendigkeit für einstellige&
,|
,^
, oder~
entweder Teil einer Erklärung zu sein. Für Typen, die den.
Elementauswahloperator verwenden, verwenden wir die Tagsstruct
undunion
in der Deklaration. Für Typen, die den->
Operator verwenden, verwenden wir die Tagsstruct
undunion
in Verbindung mit dem*
Operator im Deklarator.*iptr
, der den Zeiger des Typedef-Namens angibt.quelle
Es ist wahr, dass es für den
*
Bediener zwei Bedeutungen gibt . Es ist nicht wahr, dass dies die einzigen Bedeutungen des*
Tokens sind .In einer Erklärung wie
das
*
ist kein Operator; Es ist Teil der Syntax einer Deklaration.Die Deklarationssyntax von C soll die Ausdruckssyntax widerspiegeln, sodass die obige Deklaration als "
*p
vom Typint
" gelesen werden kann , woraus wir schließen können, dass siep
vom Typ istint*
. Dies ist jedoch keine feste Regel und wird nirgendwo im Standard angegeben. Stattdessen wird die Syntax von Deklarationen unabhängig von der Syntax von Ausdrücken eigenständig definiert. Aus diesem Grund können beispielsweise die meisten Operatoren, die in Ausdrücken vorkommen können, in Deklarationen nicht mit derselben Bedeutung angezeigt werden (es sei denn, sie sind Teil eines Ausdrucks, der Teil der Deklaration ist, wie der+
Operator inint array[2+2];
).Ein Fall, in dem das Prinzip "Deklarationsspiegel verwenden" nicht ganz funktioniert, ist:
wo
arr[10]
wäre vom Typ,int
wenn es existieren würde .Und tatsächlich gibt es noch eine andere Verwendung des
*
Tokens. Ein Array-Parameter kann mit deklariert werden[*]
, um ein Array mit variabler Länge anzugeben. (Dies wurde in C99 hinzugefügt.) Dies*
ist weder eine Multiplikation noch eine Dereferenzierung. Ich vermute, es wurde von der Shell-Wildcard-Syntax inspiriert.quelle
int *p = 0;
ähnelt der Verwendung * p = 0; `, aber die Bedeutungen sind sehr unterschiedlich.int*
).