2013-02-27 27 views
68

Stavo solo passando attraverso un codice su Internet ed ho trovato questo:dichiarazione C Complesso

float * (*(*foo())[SIZE][SIZE])() 

Come posso leggere questa dichiarazione? Esiste un insieme specifico di regole per leggere dichiarazioni così complesse?

+21

[regola spirale] (http://c-faq.com/decl/spiral.anderson.html) –

+16

http://cdecl.org/ – juanchopanza

+0

usa http://cdecl.org/ – 999k

risposta

117

non ho fatto in un istante!

Inizia con foo e vai a destra.

float * (*(*foo())[SIZE][SIZE])()

foo è una funzione senza argomenti ...

non può andare a destra dal momento che c'è una parentesi chiusa.Andate a sinistra:

float * (*(* foo())[SIZE][SIZE])()

foo è una funzione senza argomenti restituisce un puntatore

non possono andare a sinistra ulteriormente, quindi cerchiamo di attraversare la parentesi e andare di nuovo a destra

float * (*(* foo())[SIZE][SIZE])() float * (*(* foo())[SIZE][SIZE])() float * (*(* foo())[SIZE][SIZE])()

foo è una funzione senza argomenti ritornano un puntatore a una matrice di matrici dimensioni del FORMATO ...

Chiusura parentesi raggiunto , nuovamente a sinistra per raggiungere il simbolo di un puntatore:

float * (*(* foo())[SIZE][SIZE])()

foo è una funzione senza argomenti che ritornano un puntatore a un array di array dimensioni di puntatori dimensione per ...

nuovo

parentesi aperta, in modo che si attraversa e andare di nuovo a destra:

float *(*(* foo())[SIZE][SIZE])() float *(*(* foo())[SIZE][SIZE])()

foo è una funzione senza argomenti ritornano un puntatore a una matrice di matrici dimensioni di puntatori SIZE a una funzione senza argomenti ...

e lasciati alla fine

float * (*(* foo())[SIZE][SIZE])()

foo è una funzione senza argomenti che ritornano un puntatore a un array di array dimensioni di puntatori dimensione per una funzione senza argomenti restituisce un puntatore a galleggiare


E chi ha scritto che, si prega di insegnargli a usare 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(); 
+57

+1 per "E chiunque l'abbia scritto, p lease gli insegna ad usare typedef " –

+2

Si noti che la parte 'no arguments' è corretta solo per C++; per C, significa "elenco di argomenti non specificato" (ma non può essere una funzione variadica perché questi devono avere un prototipo completo in ambito, anche in C). –

3

In generale, si potrebbe provare cdecl.org ma avresti bisogno di sostituire SIZE

Dire di scambiare SIZE per 12, si otterrebbe:

dichiarare foo come funzione che restituisce puntatore a vettore 12 di matrice 12 del puntatore per restituire il puntatore al float

Non sono sicuro che ti aiuti davvero!

Due osservazioni qui:

  1. Sto indovinando che questo codice non ha avuto un commento accanto spiegando qual è lo scopo di esso era (cioè non la spiegazione tecnica di ciò che è, ma quello che è raggiungimento da un punto di vista funzionale/lavorativo) Se un programmatore ha bisogno di usare qualcosa di così complesso, dovrebbe essere abbastanza buono da spiegare ai futuri manutentori quale scopo serve.
  2. Certamente in C++ ci sono modi più ovvi e probabilmente più sicuri per ottenere la stessa cosa.
+3

Ciò è dovuto al "SIZE", devi invece usare letterale (e sostituirlo tu stesso con la costante dopo) –

+0

sostituire SIZE con un numero !! – Kaunteya

+0

Risposta modificata - grazie per il tuo feedback –

6

Secondo cdecl.org

dichiarare foo come funzione che restituisce puntatore a vettore dimensione della matrice SIZE di puntatore a funzione puntatore tornare a galleggiare

Utilizzare la regola spirale in Luchian Grigore se vuoi decodificarlo a mano.

1

da http://cdecl.org/

dichiarare foo come funzione che restituisce puntatore a matrice di dimensione di matrice di dimensione di puntatore a funzione che restituisce puntatore a galleggiare

4

La cosa migliore da fare qui è convertito ad una serie di typedef.

typedef float * fnReturningPointerToFloat(); 
typedef fnReturningPointerToFloat* fnArray[SIZE][SIZE]; 
fnArray* foo(); 
+2

Mi ci è voluto più di un minuto per farlo. – QuentinUK

97

regola standard: trovare l'identificatore più a sinistra e il tuo lavoro fuori, ricordando che [] e () legano prima *:

  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 

Quindi immaginate di avere un sacco di funzioni che ritornano puntatori a float:

float *quux(); 
float *bar(); 
float *bletch(); 
float *blurga(); 

Diciamo che si desidera memorizzare loro in una tabella 2x2:

float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga}; 

tab è una dimensione matrice di dimensione x di puntatori a funzioni che ritornano puntatori a float.

Ora decidiamo che vogliamo una funzione per restituire un puntatore a quel tavolo:

float *(*(*foo())[SIZE][SIZE])() 
{ 
    static float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga}; 
    return &tab; 
} 

Nota che si potrebbe avere diverse funzioni che costruiscono tavoli di diverse funzioni, oppure organizzare le stesse funzioni in modo diverso:

float *(*(*qwerbl())[SIZE][SIZE])() 
{ 
    static float *(*tab[SIZE][SIZE])() = {blurga, bletch, bar, quux}; 
    return tab; 
} 

che è l'unica ragione per cui posso pensare di fare qualcosa di simile. Non dovresti vedere tipi come questo in natura molto spesso (anche se saltano fuori occasionalmente, e sono stato colpevole di scrivere qualcosa di simile atroce).

+1

qwerbl? Hai quasi esaurito i nomi di variabili generiche, non l'hai fatto :-) +1 per la logica. E sono sicuro che i tipi "profondamente correlati" appaiono abbastanza spesso, ma di solito coinvolgono anche strutture o classi, il che rende il problema di denominazione andare via naturalmente - come farebbe qui quando si introducono alcuni typedef. – Kos

+0

@Kos: sì. Non ho ancora avuto la mia RDA di caffeina, non ho potuto inventare niente di meglio. –

+1

Wikipedia ha una [lista di variabili metasintattiche] (http://en.wikipedia.org/wiki/Metasyntactic_variable#English) in modo da non esaurire: foo, bar, baz, qux, quux, corge, grault, garply , waldo, fred, plugh, xyzzy, thud. –

2

Questo documento mi gaves il miglior indizio su come facilmente pronti ogni dichiarazione C:

http://c-faq.com/decl/spiral.anderson.html

ci sono tre semplici passi da seguire:

  • partire con l'ignoto elemento, muovere in una spirale/senso orario; quando ecountering i seguenti elementi sostituirli con i corrispondenti rendiconti inglese:

    • [X] o [] size => Array X ... o matrice formato indefinito di ...

    • (type1, type2) => funzione anabbagliante tipo1 e tipo2 ritorno ...

    • * => puntatore (s) per ...

  • Continuare a fare questo in una spirale/senso orario fino a quando tutti i token sono stati coperti.

  • Risolvi sempre tutto in parentesi prima!

Esempio:

   +-------+ 
      | +-+ | 
      |^| | 
     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!