Ich habe gerade einen Code im Internet durchgesehen und Folgendes gefunden:
float * (*(*foo())[SIZE][SIZE])()
Wie lese ich diese Erklärung? Gibt es bestimmte Regeln zum Lesen derart komplexer Erklärungen?
Ich habe gerade einen Code im Internet durchgesehen und Folgendes gefunden:
float * (*(*foo())[SIZE][SIZE])()
Wie lese ich diese Erklärung? Gibt es bestimmte Regeln zum Lesen derart komplexer Erklärungen?
Antworten:
Ich habe das schon eine Weile nicht mehr gemacht!
Beginnen Sie mit foo
und gehen Sie nach rechts.
float * (*(*
foo()
)[SIZE][SIZE])()
foo ist eine Funktion ohne Argumente ...
Kann nicht richtig gehen, da es eine schließende Klammer gibt. Geh nach links:
float * (*(
* foo()
)[SIZE][SIZE])()
foo ist eine Funktion ohne Argumente, die einen Zeiger zurückgeben
Ich kann nicht weiter nach links gehen, also kreuzen wir die Klammern und gehen wieder nach rechts
float * (*
(* foo())
[SIZE][SIZE])()
float * (*
(* foo())[SIZE]
[SIZE])()
float * (*
(* foo())[SIZE][SIZE]
)()
foo ist eine Funktion ohne Argumente, die einen Zeiger auf ein Array von SIZE-Arrays von SIZE zurückgibt ...
Schließende Klammer erreicht, wieder links, um ein Zeigersymbol zu erreichen:
float * (
*(* foo())[SIZE][SIZE]
)()
foo ist eine Funktion ohne Argumente, die einen Zeiger auf ein Array von SIZE-Arrays von SIZE-Zeigern auf ... zurückgibt.
Wieder die linke Klammer, also kreuzen wir sie und gehen wieder nach rechts:
float *
( *(* foo())[SIZE][SIZE])
()
float *
( *(* foo())[SIZE][SIZE])()
foo ist eine Funktion ohne Argumente, die einen Zeiger auf ein Array von SIZE-Arrays mit SIZE-Zeigern auf eine Funktion ohne Argumente zurückgibt ...
Und bis zum Ende gelassen
float * ( *(* foo())[SIZE][SIZE])()
foo ist eine Funktion ohne Argumente, die einen Zeiger auf ein Array von SIZE-Arrays mit SIZE-Zeigern auf eine Funktion zurückgibt, ohne Argumente, die einen Zeiger auf float zurückgeben
Und wer auch immer das geschrieben hat, bitte bringen Sie ihm bei, Folgendes zu verwenden typedef
:
// Function that returns a pointer to float
typedef float* PFloatFunc ();
// Array of pointers to PFloatFunc functions
typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE];
// Function that returns a pointer to a PFloatFuncArray2D
PFloatFuncArray2D* foo();
Standardregel: Finden Sie die Kennung ganz links und arbeiten Sie sich heraus, merken Sie sich das []
und ()
binden Sie vorher *
:
foo -- foo
foo() -- is a function
*foo() -- returning a pointer
(*foo())[SIZE] -- to a SIZE-element array
(*foo())[SIZE][SIZE] -- of SIZE-element arrays
*(*foo())[SIZE][SIZE] -- of pointers
(*(*foo())[SIZE][SIZE])() -- to functions
* (*(*foo())[SIZE][SIZE])() -- returning pointers
float * (*(*foo())[SIZE][SIZE])(); -- to float
Stellen Sie sich vor, Sie haben eine Reihe von Funktionen, die Zeiger zurückgeben auf float
:
float *quux();
float *bar();
float *bletch();
float *blurga();
Angenommen, Sie möchten sie in einer 2x2-Tabelle speichern:
float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
tab
ist ein SIZE x SIZE-Array von Zeigern auf Funktionen, auf die Zeiger zurückgegeben werden float
.
Nun wollen wir entscheiden, dass eine Funktion einen Zeiger auf diese Tabelle zurückgibt:
float *(*(*foo())[SIZE][SIZE])()
{
static float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
return &tab;
}
Beachten Sie, dass Sie mehrere Funktionen haben können, die Tabellen mit unterschiedlichen Funktionen erstellen oder dieselben Funktionen unterschiedlich organisieren:
float *(*(*qwerbl())[SIZE][SIZE])()
{
static float *(*tab[SIZE][SIZE])() = {blurga, bletch, bar, quux};
return tab;
}
Das ist der einzige Grund, warum ich mir so etwas vorstellen kann. Sie sollten solche Typen nicht sehr oft in freier Wildbahn sehen (obwohl sie gelegentlich auftauchen und ich mich schuldig gemacht habe, etwas ähnlich Abscheuliches geschrieben zu haben).
Laut cdecl.org
Deklarieren Sie foo als Funktionsrückgabezeiger auf Array. GRÖSSE des Arrays GRÖSSE des Zeigers auf Funktionsrückgabezeiger auf Float
Verwenden Sie die Spiralregel von Luchian Grigore, wenn Sie sie von Hand dekodieren möchten.
Im Allgemeinen könnten Sie cdecl.org ausprobieren, aber Sie müssten es ersetzenSIZE
Angenommen, Sie tauschen SIZE
gegen 12, dann erhalten Sie:
deklarieren Sie foo als Funktionsrückgabezeiger auf Array 12 von Array 12 von Zeiger auf Funktionsrückgabezeiger auf float
Ich bin mir nicht sicher, ob dir das wirklich hilft!
Zwei Beobachtungen hier:
Dieses Dokument gibt mir den besten Hinweis darauf, wie ich eine C-Deklaration einfach erstellen kann:
http://c-faq.com/decl/spiral.anderson.html
Es gibt drei einfache Schritte:
Beginnen Sie mit dem unbekannten Element und bewegen Sie sich spiralförmig / im Uhrzeigersinn. Wenn Sie auf folgende Elemente stoßen, ersetzen Sie diese durch die entsprechenden englischen Aussagen:
[X]
oder[]
=> Array X Größe von ... oder Array undefinierte Größe von ...
(type1, type2)
=> Funktion übergibt Typ1 und Typ2 und gibt ...
*
=> Zeiger auf ...Machen Sie dies spiralförmig / im Uhrzeigersinn, bis alle Token bedeckt sind.
Lösen Sie immer zuerst alles in Klammern!
Beispiel:
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
Question we ask ourselves: What is str?
``str is an...
- We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
``str is an array 10 of...
- Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
``str is an array 10 of pointers to...
- Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
``str is an array 10 of pointers to char''
We have now ``visited'' every token; therefore we are done!
Obwohl die meisten der obigen Antworten gut genug sind, fehlen vollständige Regeln für die Dekodierung komplexer C-Deklarationen. Ich habe unten einen vollständigen Satz bereitgestellt, um jede komplexe C-Deklaration zu dekodieren. Dieses Regelwerk basiert tatsächlich auf der Priorität von Operatoren. Regeln wie rechte Spiralregeln können als Abkürzung für diese Regeln angesehen werden.
Vor allem müssen wir einige Dinge wissen, um die Deklaration zu entschlüsseln.
'Grundtyp' einer Erklärung
Die AC-Deklaration hat immer nur einen grundlegenden Deklarationstyp. Dies ist die am weitesten links stehende Position einer Erklärung. Zum Beispiel -
int a
- Grundtyp ist 'int'float *p
- Grundtyp ist 'float'char (*p)[3]
- Grundtyp ist 'char'Vorrang und Assoziativität
Als nächstes müssen wir die Rangfolge der wissen ()
, []
und *
- Dereferenzierungsoperator
()
, []
- Assoziativität ist von links nach rechts*
- Assoziativität ist von rechts nach linksPhrase, die jedem der obigen Operatoren entspricht
Als nächstes müssen wir die decodierte Phrase kennen, die jedem Operator entspricht. Beispiele werden diesen Punkt klar machen.
()
- Funktionsrückgabe[SIZE]
- Array von GRÖSSE*
- Zeiger aufBefolgen Sie nun die folgenden Regeln, um die Deklaration zu dekodieren
Schreiben Sie immer zuerst den Variablennamen, gefolgt von einem 'ist'.
Zum Beispiel -
int a
- a ist ...float *p
- p ist ...char (*p)[3]
- p ist ...Beenden Sie immer mit dem Basistyp
Zum Beispiel -
int a
- a ist ... intfloat *p
- p ist ... schwebenchar (*p)[3]
- p ist ... charFüllen Sie nun den Teil dazwischen mit den folgenden Unterschritten
Folgen Sie ausgehend vom Namen der Priorität und Assoziativität des Operators, um den Operator mit der nächsthöheren Priorität auszuwählen, und hängen Sie die entsprechende Phrase an den mittleren Teil der decodierten Zeichenfolge an.
Wiederholen Sie den obigen Unterschritt für die verbleibende Deklaration, bis der Dekodierungsprozess abgeschlossen ist
ANMERKUNG 1: Der Einfachheit halber habe ich die Argumente der Funktion ignoriert, sie können jedoch direkt nach der entsprechenden Phrase eingefügt werden ()
.
ANMERKUNG 2: Parenthesis ( ()
) ändert die Prioritätsreihenfolge von Operatoren wie bei jedem arithmetischen Ausdruck.
ANMERKUNG 3: Sie können in der dekodierten Deklaration Klammern verwenden, um die Lesbarkeit zu verbessern (ich habe dies in einigen Beispielen unten getan). Stellen Sie sich jede Menge von () als eine Einheit vor.
ANMERKUNG 4: Ein n-dimensionales Array ist tatsächlich ein Array von Arrays von ... (n-1-mal) Arrays . Zum Beispiel ist A [2] [3] - A ein Array von 2 (Array von 3 int), dh A ist ein Array von 2 Elementen, wobei jedes Element ein Array ist, das 3 ganze Zahlen enthält
Beispiele
int a
- a ist intfloat *p
- p ist der Zeiger auf floatchar (*p)[3]
- p ist ein Zeiger auf ein Array mit 3 ZeichenEinige komplexe Deklarationsbeispiele
int **p[10]
- p ist ein Array von 10 Zeigern auf Zeiger auf intint (*p)[10]
- p ist ein Zeiger auf ein Array von 10 intint *p(char *a)
- p ist ein Funktionsrückgabezeiger auf intint (*p(char*a))[10]
- p gibt die Funktion zurück (Zeiger auf (Array von 10 int))int *(*p)()
- p ist Zeiger auf (Funktionsrückgabe (Zeiger auf int))int (*p()[20])[10]
- p ist eine Funktionsrückgabe (Array von 20 (Zeiger auf (Array von 10 int)))Dieser Regelsatz kann auch mit verwendet werden const
- const qualifier ändert den Begriff links davon (falls vorhanden), andernfalls ändert er den Begriff rechts davon.
const int *p[10]
- p ist ein Array von 10 Zeigern auf int constint const *p[10]
- p ist ein Array mit 10 Zeigern auf const int (dies entspricht dem 7. Beispiel).int *const p[10]
- p ist ein Array von 10 const Zeigern auf intNun ein wirklich komplexes Beispiel, das in der Praxis nirgendwo Verwendung findet, aber dennoch zur Demonstration des Dekodierungsprozesses verwendet werden kann
char *(*(**foo[][8])())[]
- foo ist ein Array von (Array von 8 (Zeiger auf (Zeiger auf (Rückgabe der Funktion) (Zeiger auf (Array von (Zeiger auf char))))))Nun endlich Dekodierung für die in der Frage gegebene Erklärung
float * (*(*foo())[SIZE][SIZE])()
- foo gibt die Funktion zurück (Zeiger auf (Array von SIZE (Array von SIZE) (Zeiger auf (Funktion gibt Zeiger auf float zurück)))
Das Folgende ist der Link für den Artikel, aus dem ich diesen Dekodierungsprozess gelesen habe
Beispiel 10 wurde diesem Artikel entnommen
Deklarieren Sie foo als Funktionsrückgabezeiger auf Array. GRÖSSE des Arrays GRÖSSE des Zeigers auf Funktionsrückgabezeiger auf Float