Convenzioni di denominazione utilizzate per variabili e funzioni in C [chiuso]

11

Durante la codifica di un grande progetto in C mi sono imbattuto in un problema. Se continuo a scrivere più codice, ci sarà un tempo in cui sarà difficile per me organizzare il codice. Intendo dire che la denominazione di funzioni e variabili per diverse parti del programma può sembrare confusa.

Quindi stavo pensando se ci sono utili convenzioni di denominazione che posso usare per variabili e funzioni C?

La maggior parte delle lingue suggerisce una convenzione di denominazione. Ma per C l'unica cosa che ho letto fino ad ora è che i nomi dovrebbero essere descrittivi per la leggibilità del codice.

EDIT:

Esempi di alcuni esempi di convenzioni di denominazione suggerite:

Ho letto alcune convenzioni di denominazione per java da qualche parte ma non ricordo dove.

    
posta Aseem Bansal 28.06.2013 - 20:36
fonte

6 risposte

15

If I keep on writing more code then there will be a time when it will be difficult for me to organize the code.

Questo è il tuo problema: ottieni l'organizzazione giusta e lo stile dovrebbe fluire più facilmente.

Non aspetta per organizzare il tuo codice: mantieni il codice organizzato mentre procedi. Sebbene il linguaggio non lo faccia per te, il codice dovrebbe comunque essere organizzato in moduli con basso accoppiamento e alta coesione.

Questi moduli forniscono naturalmente uno spazio dei nomi. Abbrevia il nome del modulo (se è lungo) e prefisso i nomi delle funzioni con il loro modulo per evitare collisioni.

A livello dei singoli identificatori, questi sono all'incirca in ordine crescente di soggettività:

  1. scegliere una convenzione e attenervisi
    • ad esempio, function_like_this(struct TypeLikeThis variable) è comune
  2. Evita decisamente la notazione ungherese (sorry JNL)

    • a meno che tu non voglia utilizzarlo come originariamente previsto, il che significa che la notazione app di Simonyi piuttosto che la terribile versione di sistema

      Perché? Potrei scrivere un saggio su questo argomento, ma ti suggerisco invece di leggere questo articolo di Joel Spolsky, e poi cacciare ancora un po 'se sei interessato. C'è un link alla carta originale di Simonyi in fondo.

  3. evita typedefs del puntatore a meno che non siano tipi di cookie veramente opachi - confondono solo le cose

    struct Type *ok;
    typedef struct Type *TypePtr;
    TypePtr yuck;
    

    Che cosa intendo con un tipo di cookie opaco ? Intendo qualcosa usato all'interno di un modulo (o libreria, o qualsiasi altra cosa) che deve essere passato al codice client, ma quel codice client non può usare direttamente. Lo restituisce semplicemente alla biblioteca.

    Ad esempio, una libreria di database potrebbe esporre un'interfaccia come

    /* Lots of buffering, IPC and metadata magic held in here.
       No, you don't get to look inside. */
    struct DBContextT;
    /* In fact, you only ever get a pointer, so let's give it a nice name */
    typedef struct DBContexT *DBContext;
    
    DBContext db_allocate_context(/*maybe some optional flags?*/);
    void db_release_context(DBContext);
    int db_connect(DBContext, const char *connect);
    int db_disconnect(DBContext);
    int db_execute(DBContext, const char *sql);
    

    Ora, il contesto è opaco al codice cliente, perché non puoi guardare dentro. Devi solo restituirlo alla biblioteca. Qualcosa come FILE è anche opaco, e un descrittore di file intero è anche un cookie , ma non è opaco.

Una nota sul design

Ho usato la frase basso accoppiamento e alta coesione sopra senza spiegazione, e mi sento un po 'male a riguardo. Puoi cercarlo e probabilmente trovare dei buoni risultati, ma proverò ad affrontarlo brevemente (di nuovo, potrei scrivere un tema ma cercherò di non farlo).

La libreria DB disegnata sopra mostra basso accoppiamento perché espone una piccola interfaccia al mondo esterno. Nascondendo i dettagli dell'implementazione (in parte con il trucco opaco dei cookie), impedisce al codice client di dipendere da questi dettagli.

Immaginate invece del cookie opaco, dichiariamo la struttura di contesto in modo che il suo contenuto sia visibile e che includa un descrittore di file socket per una connessione TCP al database. Se successivamente modifichiamo l'implementazione per supportare l'utilizzo di un segmento di memoria condivisa quando il DB è in esecuzione sulla stessa macchina, il client deve essere ricompilato anziché semplicemente ricollegato. Ancora peggio, il client potrebbe aver avviato utilizzando il descrittore di file, ad esempio chiamando setsockopt per modificare la dimensione del buffer predefinita, e ora ha anche bisogno di una modifica del codice. Tutti questi dettagli dovrebbero essere nascosti all'interno del nostro modulo dove sono pratici, e questo dà un basso accoppiamento tra moduli.

L'esempio mostra anche alta coesione , in quanto tutti i metodi nel modulo riguardano la stessa attività (accesso al DB). Ciò significa che solo il codice che ha bisogno di per conoscere i dettagli dell'implementazione (cioè il contenuto del nostro cookie) ha effettivamente accesso ad essi, il che semplifica il debugging.

Puoi anche vedere che avere un singolo problema semplifica la scelta di un prefisso per raggruppare insieme queste funzioni.

Ora, dire che questo esempio è buono è facile (soprattutto perché non è nemmeno completo), ma non ti aiuta immediatamente. Il trucco è guardare, mentre scrivi ed estendi il tuo codice, per funzioni che fanno cose simili o che operano sugli stessi tipi (che potrebbero essere candidati per il proprio modulo), e anche per funzioni che fanno molte cose separate che non sono " Sono davvero correlati e potrebbero essere candidati alla separazione.

    
risposta data 29.06.2013 - 00:27
fonte
5

A mio parere, il 90% del problema di denominazione viene risolto se tenga conto di tre cose: a) rende i nomi delle variabili e delle funzioni il più descrittivi possibile, b) essere coerente per tutto il codice (ad esempio, se una funzione è denominata addNumbers, una seconda funzione deve essere denominata moltipliclyNumbers e non numbersMul) e c) provare a rendere i nomi brevi se possibile, poiché è necessario digitarli

Detto questo se vuoi dare un'occhiata ad altri aspetti su questo argomento, la pagina di Wikipedia su Convenzioni sui nomi ha una buona lista di cose che dovresti tenere a mente. Ha anche una sezione su C e C ++:

In C and C++, keywords and standard library identifiers are mostly lowercase. In the C standard library, abbreviated names are the most common (e.g. isalnum for a function testing whether a character is alphanumeric), while the C++ standard library often uses an underscore as a word separator (e.g. out_of_range). Identifiers representing macros are, by convention, written using only upper case letters and underscores (this is related to the convention in many programming languages of using all-upper-case identifiers for constants). Names containing double underscore or beginning with an underscore and a capital letter are reserved for implementation (compiler, standard library) and should not be used (e.g. reserved__ or _Reserved).[5][6] This is superficially similar to stropping, but the semantics differ: the underscores are part of the value of the identifier, rather than being quoting characters (as is stropping): the value of __foo is __foo (which is reserved), not foo (but in a different namespace).

    
risposta data 28.06.2013 - 20:50
fonte
4

L'unico vincolo difficile in C è che non ci sono spazi dei nomi. Pertanto, devi trovare un modo per rendere la funzione rename() della tua libreria filesystem diversa dalla funzione rename() della tua libreria media . La solita soluzione è un prefisso, ad esempio: filesystem_rename() e media_rename() .

L'altro consiglio generale è: rimanere coerenti all'interno di un progetto o di una squadra. La leggibilità sarà migliorata.

    
risposta data 28.06.2013 - 22:37
fonte
2

SE STAI CERCANDO UN FORMATO GLOBALMENTE ACCETTATO

MISRA / JSF / AUTOSAR copre quasi il 100% di qualsiasi standard di settore per la denominazione e l'organizzazione del codice C / C ++. Il problema è che non saranno liberi di entrare in possesso, ad esempio, ognuna delle guide costa dei soldi. So che il libro standard di codifica MISRA 2008 C / C ++ costa probabilmente circa 50 USD.

Puoi pensare a questi come referenziazione di Harvard per la bibliografia e la lettura delle aggiunte quando scrivi un diario. Ho usato MISRA ed è un buon modo per nominare funzioni e variabili e organizzarle per un uso corretto.

SE STAI CERCANDO QUALCOSA DI TEMPORANEA

Suppongo che i riferimenti forniti per Python e Java siano a posto. Ho visto persone che adottavano commenti in stile javadoc, nomi e organizzazione del codice. In effetti, nel mio ultimo progetto, ho dovuto scrivere codice C ++ in funzioni / nomi di variabili simili a Java. Due motivi dietro questo:

1) Era apparentemente più facile da seguire.

2) I requisiti del codice di produzione non hanno toccato la base degli standard del sistema software safety-critical.

3) Il codice legacy era (in qualche modo) in quel formato.

4) Doxygen ha permesso commenti Javadoc sytle. In quel momento, stavamo usando doxygen per generare documentazione per i ragazzi di produzione.

Molti programmatori saranno contrari a questo, ma personalmente penso che non ci sia nulla di sbagliato nell'adottare la funzione di stile javadoc / la denominazione delle variabili in C / C ++. SÌ, il modo di organizzare il controllo del flusso, la sicurezza del filo, ecc. Deve essere affrontato a prescindere. Tuttavia, non sono un candidato qui. Inoltre, non so quanto siano severi i requisiti di formato del codice di produzione. Senza dirottarlo in un'area fuori tema, ti suggerisco di rivedere le tue esigenze, scoprire come dipendono da una specifica convenzione di denominazione e seguire una soluzione menzionata nelle mie e in quelle degli altri

Spero che questo sia stato di aiuto !?

    
risposta data 29.06.2013 - 22:32
fonte
0

Poche cose importanti da prendere in considerazione durante la denominazione;

  1. Guarda il tipo actionObject o ObjectAction. (Object Not for C. Ma in generale quando vai ad altre lingue orientate agli oggetti) Questo dovrebbe aiutare

  2. Rest sarebbe BE COSTANTE, breve e descrittivo di sicuro.

  3. Inoltre, avere un unico scopo di ogni variabile e funzione definita, Ad esempio: se per memorizzare temporaneamente un valore, chiamarlo nTempVal per int
  4. Le variabili dovrebbero essere nome e i metodi dovrebbero essere verbo.
risposta data 28.06.2013 - 21:50
fonte
0

La maggior parte delle risposte è buona, ma voglio dire alcune cose sulle convenzioni di denominazione per le librerie e file inclusi, simile all'utilizzo di spazi dei nomi in altri linguaggi come C ++ o Java:

Se si crea una libreria, trovare un prefisso comune per i simboli esportati, ovvero funzioni globali, typedef e variabili. Ciò impedirà gli scontri con altre librerie e identificherà le funzioni come provenienti dal tuo. Questo è un po 'di app notazioni ungheresi.

Forse andare ancora oltre e raggruppare i simboli esportati: libcurl usa curl_ * per i simboli globali, curl_easy_ *, curl_multi_ * e curl_share_ * per le diverse interfacce. Quindi oltre a usare curl_ * per tutte le funzioni, hanno aggiunto un altro livello di "namespace" per le diverse interfacce: chiamare una funzione di curl_easy_ * su un handle di curl_multi_ * ora sembra errato, vedere i nomi delle funzioni su link

Mantenendo le regole per i simboli esportati, dovresti usare quelli per le funzioni statiche nei file #include ed: Cerca di trovare un prefisso comune per queste funzioni. Forse hai funzioni di utility per le stringhe statiche in un file chiamato "my_string"? Prefix tutte queste funzioni con my_string _ *.

    
risposta data 29.06.2013 - 10:37
fonte

Leggi altre domande sui tag