Come leggi le dichiarazioni C?

Ho sentito parlare di alcuni metodi, ma nessuno di loro è rimasto bloccato. Personalmente cerco di evitare tipi complessi in C e provo a romperli in typedef componente.

Ora mi trovo a dover mantenere un codice legacy da un cosiddetto “programmatore a tre stelle” e sto facendo fatica a leggere alcuni dei codici [] [].

Come leggi le dichiarazioni C complesse?

Questo articolo spiega una relativamente semplice 7 regole che ti consente di leggere qualsiasi dichiarazione C, se ti trovi a desiderare o se devi farlo manualmente: http://www.ericgiguere.com/articles/reading-c-declarations.html

  1. Trova l’identificatore. Questo è il tuo punto di partenza. Su un pezzo di carta, scrivi “declare identificatore come”.
  2. Guarda a destra. Se non c’è niente lì, o c’è una parentesi chiusa “)”, vai al passaggio 4.
  3. Ora sei posizionato su un array (sinistra parentesi) o funzione (sinistra parentesi) descrittore. Può esserci una sequenza di questi, che termina con una parentesi tonda non abbinata o con la fine del dichiaratore (un punto e virgola o un “=” per l’inizializzazione). Per ognuno di questi descrittori, leggendo da sinistra a destra:

    • se un array vuoto “[]”, scrivi “array di”
    • se una matrice con una dimensione, scrivere “dimensione dell’array di”
    • se una funzione “()”, scrive “restituisce la funzione”

    Fermati alla parentesi non abbinata o alla fine del dichiarante, a seconda di cosa viene prima.

  4. Ritorna alla posizione di partenza e guarda a sinistra. Se non c’è niente lì, o c’è una parentesi sinistra “(“, vai al punto 6.
  5. Ora sei posizionato su un descrittore del puntatore, “*”. Potrebbe esserci una sequenza di questi a sinistra, che termina con una parentesi sinistra non abbinata “(” o l’inizio del dichiaratore .Lettura da destra a sinistra, per ogni descrittore puntatore scrivere “puntatore a”. Fermarsi alla parentesi non corrispondente o l’inizio del dichiaratore, qualunque sia il primo.
  6. A questo punto hai un’espressione tra parentesi o il dichiaratore completo. Se hai un’espressione tra parentesi, considerala come nuovo punto di partenza e torna al passaggio 2.
  7. Annota lo specificatore del tipo. Stop.

Se stai bene con uno strumento, poi io suggerisco di usare il programma cdecl : http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html

Io generalmente uso quella che a volte viene chiamata la “regola destrorsa della mano destra”. Va così:

  • Inizia dall’identificatore.
  • Vai immediatamente a destra di esso.
  • Quindi spostati in senso orario e vieni sul lato sinistro.
  • Sposta in senso orario e vieni sul lato destro.
  • Fallo finché la dichiarazione non è stata analizzata completamente.

C’è un’ulteriore meta-regola che deve essere curata:

  • Se ci sono parentesi, completare ogni livello di parentesi prima di trasferirsi.

Qui, “andare” e “spostare” da qualche parte significa leggere il simbolo lì. Le regole per questo sono:

  • * – puntatore a
  • () – funzione di ritorno
  • (int, int) – funzione che esegue due intro e restituisce
  • int , char , ecc. – int , char , ecc.
  • [] – array di
  • [10] – array di dieci
  • eccetera.

Ad esempio, int* (*xyz[10])(int*, char) viene letto come:

xyz è un

serie di dieci

puntatore a

funzione prendendo un int * e un char e ritornando

un int *

Una sola parola: cdecl

Dannato, battuto da 15 secondi!

Cdecl (e c ++ decl) è un programma per codificare e decodificare dichiarazioni di tipo C (o C ++).

http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html

Indietro quando stavo facendo C, ho fatto uso di un programma chiamato “cdecl”. Sembra che sia in Ubuntu Linux nel pacchetto cutils o cdecl, ed è probabilmente disponibile altrove.

cdecl offre un’interfaccia a riga di comando quindi proviamo:

 cdecl> explain int ***c[][] declare c as array of array of pointer to pointer to pointer to int 

un altro esempio

  explain int (*IMP)(ID,SEL) declare IMP as pointer to function (ID, SEL) returning int 

Tuttavia, nel libro “C Deep Secrets” c’è un intero capitolo, intitolato “Decodificare le dichiarazioni in C.

Saluti Friedrich

C’è anche una versione basata su Web di cdecl, che è piuttosto liscia.

I comuni problemi di leggibilità includono i puntatori di funzione e il fatto che gli array sono realmente indicatori e che gli array multidimensionali sono in realtà matrici a singola dimensione (che sono in realtà dei puntatori). Spero che ne aiuti qualcuno.

In ogni caso, ogni volta che capisci le dichiarazioni, forse puoi trovare un modo per semplificarle per renderle più leggibili per il prossimo.

La soluzione automatizzata è cdecl.

In generale, dichiari una variabile nel modo in cui la usi. Ad esempio, è ansible annullare il riferimento a un puntatore p come in:

 char c = * p

lo dichiari in un modo simile:

 char * p;

Lo stesso vale per i puntatori di funzioni pelose. Diciamo che f è un buon vecchio “puntatore alla funzione che restituisce il puntatore a int” e una dichiarazione esterna solo per essere divertente. È un puntatore a una funzione, quindi iniziamo con:

 extern * f ();

Restituisce un puntatore a un int, quindi da qualche parte lì davanti c’è

 extern int * * f ();  // XXX non ancora del tutto

Ora qual è l’associatività corretta? Non posso mai ricordare, quindi usa una parentesi.

 extern (int *) (* f) ();

Dichiaralo nel modo in cui lo usi.

Leggi da destra a sinistra.

 ***code[][] 
  • codice [] [] è una matrice multidimensionale
  • * codice [] [] è un puntatore a schieramento multidimensionale
  • ** codice [] [] è un puntatore di array multidimensionale a un puntatore
  • *** codice [] [] è un puntatore di array multidimensionale a un puntatore a un puntatore

Ho appena trovato una sezione illuminante in ” Lo sviluppo del linguaggio C “:

Per ogni object di un tipo così composto, c’era già un modo per menzionare l’object sottostante: indicizzare l’array, chiamare la funzione, utilizzare l’operatore di riferimento indiretto sul puntatore. Il ragionamento analogico ha portato ad una syntax di dichiarazione per i nomi che rispecchiano quella della syntax di espressione in cui i nomi appaiono tipicamente. Così,

int i, *pi, **ppi;

dichiara un numero intero, un puntatore a un numero intero, un puntatore a un puntatore a un numero intero. La syntax di queste dichiarazioni riflette l’osservazione che i, * pi e ** ppi generano tutti un tipo int quando usati in un’espressione. Allo stesso modo,

int f(), *f(), (*f)();

dichiarare una funzione che restituisce un intero, una funzione che restituisce un puntatore a un numero intero, un puntatore a una funzione che restituisce un intero;

int *api[10], (*pai)[10];

dichiara un array di puntatori agli interi e un puntatore a un array di numeri interi. In tutti questi casi la dichiarazione di una variabile assomiglia al suo utilizzo in un’espressione il cui tipo è quello nominato all’inizio della dichiarazione.