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

Chiusa. Questa domanda è fuori tema . Attualmente non accetta risposte.

Commenti

  • Cita alcuni esempi di linguaggi con convenzioni di denominazione suggerite. E dove possiamo trovare quelle convenzioni di denominazione.
  • @Philip Aggiunti esempi
  • Non dovrebbero ' essere un problema con le variabili mentre non ' t utilizzare globali. E per i nomi delle funzioni: se il nome del modulo ' è order.c, puoi denominare le funzioni order_add(), order_del() e simili. Potrebbero esserci vecchi sistemi che ti dicono che il nome deve essere univoco entro i primi 8 caratteri. Quando in seguito passi a c ++ per sbaglio, ' adorerai scrivere order::add() e order::del() quindi.

Rispondi

Se continuo scrivendo più codice poi ci sarà un momento in cui sarà difficile per me organizzare il codice.

Questo è il tuo problema: crea lorganizzazione giusta, e lo stile dovrebbe scorrere più facilmente.

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

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

A livello di identificatori individuali, questi sono approssimativamente in ordine crescente di soggettività:

  1. scegli una convenzione e rispettala
    • ad es. function_like_this(struct TypeLikeThis variable) è comune
  2. evita decisamente la notazione ungherese (scusa JNL)

    • a meno che tu non sia disposto a usarla come originariamente previsto, il che significa la notazione app di Simonyi invece che la terribile versione dei sistemi

      Perché? Potrei scrivere un saggio su questo, ma ti suggerirò invece di leggere questo articolo di Joel Spolsky, e poi dare unocchiata in giro se sei interessato. Cè “un link al documento originale di Simonyi” in fondo.

  3. Evita i typedef puntatore a meno che non siano tipi di cookie veramente opachi – sono solo confondere le cose

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

    Cosa intendo per tipo di cookie opaco ? Intendo qualcosa usato allinterno di un modulo (o libreria, o qualunque cosa) che deve essere passato al codice client, ma quel codice client non può “essere usato direttamente. Lo restituisce alla libreria.

    Ad esempio, una libreria di database potrebbe esporre uninterfaccia 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 per il codice client, perché non puoi “guardare dentro. Devi solo passarlo di nuovo alla libreria. 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 spiegazioni, e mi sento un po in colpa per questo. Puoi cercarlo e probabilmente trovare dei buoni risultati, ma cercherò di affrontarlo brevemente (di nuovo, potrei scrivere un saggio ma cercherò di non farlo).

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

Immagina invece del cookie opaco, dichiariamo la struttura del contesto in modo che i suoi contenuti siano visibili e che includa un descrittore di file socket per una connessione TCP al database. Se successivamente cambiamo limplementazione per supportare luso di un segmento di memoria condivisa quando il Il DB è in esecuzione sulla stessa macchina, il client deve essere ricompilato piuttosto che semplicemente ricollegato. Ancora peggio, il client avrebbe potuto iniziare utilizzando il descrittore di file, ad esempio chiamando setsockopt per modificare la dimensione del buffer predefinita, e ora è necessaria anche una modifica del codice. Tutti questi dettagli ils dovrebbe essere nascosto allinterno del nostro modulo dove pratico, e questo fornisce un basso accoppiamento tra moduli.

Lesempio mostra anche alta coesione , in quanto tutte le i metodi nel modulo si occupano della stessa attività (accesso al DB). Ciò significa che solo il codice che necessita di conoscere i dettagli di implementazione (cioè il contenuto del nostro cookie) ha effettivamente accesso ad essi, il che semplifica il debugging.

Puoi anche vedere che avere ununica preoccupazione ha reso facile scegliere un prefisso per raggruppare queste funzioni insieme.

Ora, dire che questo esempio è buono è facile (soprattutto perché non lo è “Non è nemmeno completo), ma non ti aiuta immediatamente. Il trucco è osservare, mentre scrivi ed estendi il codice, le funzioni che fanno cose simili o operano sugli stessi tipi (che potrebbero essere candidati per il proprio modulo), e anche le funzioni che fanno molte cose separate che non sono ” Non sono molto imparentati e potrebbero essere candidati per la divisione.

Commenti

  • Puoi aiutarmi a capire perché si evita lungherese? Sono solo curioso di saperne di più a riguardo. 🙂
  • @JNL: un commento è troppo breve per essere spiegato correttamente. Ti suggerisco di pubblicarlo come nuova domanda.
  • with low coupling and high cohesion. Che cosa significa? E per favore spiega i tipi di cookie opachi. Non ho idea di cosa significhi.
  • Ho cercato di affrontare entrambi brevemente e francamente non sono riuscito a brevità. Spero che dovrebbe farti iniziato però.
  • Rispondo dopo alcuni giorni. Ci scusiamo per questo. Ho letto la tua descrizione di low coupling and high cohesion. Quindi sostanzialmente significa incapsulare le cose quando posso e dovrebbe essere fatto in modo che il file le funzioni che effettivamente necessitano dovrebbero avere accesso. Alcune cose mi sono passate per la testa, ma penso comunque di aver capito il tuo punto.

Risposta

Secondo me 90 % del problema di denominazione viene risolto se si tengono a mente tre cose: a) rende i nomi delle variabili e delle funzioni tanto descrittivi quanto possibile, b) essere coerente in tutto il codice (ad esempio, se una funzione si chiama addNumbers, una seconda funzione dovrebbe essere chiamata multiplyNumbers e non numbersMul) e c) cerca di abbreviare i nomi, se possibile, poiché è necessario digitarli.

Detto questo, se vuoi dare unocchiata ad altri aspetti su questo argomento, la pagina di Wikipedia su Convenzioni sui nomi ha un buon elenco di cose che dovresti tieni a mente. Ha anche una sezione in C e C ++:

In C e C ++, le parole chiave e gli identificatori di libreria standard sono per lo più minuscoli. Nella libreria standard C, i nomi abbreviati sono i più comuni (ad esempio isalnum per una funzione che verifica se un carattere è alfanumerico), mentre la libreria standard C ++ utilizza spesso un trattino basso come separatore di parole (ad esempio out_of_range). Gli identificatori che rappresentano le macro sono, per convenzione, scritti utilizzando solo lettere maiuscole e trattini bassi (questo è correlato alla convenzione in molti linguaggi di programmazione di utilizzare identificatori tutti maiuscoli per le costanti). I nomi contenenti un doppio trattino basso o che iniziano con un trattino basso e una lettera maiuscola sono riservati per limplementazione (compilatore, libreria standard) e non devono essere utilizzati (ad es. Riservato__ o _Reservato). [5] [6] Questo è superficialmente simile allo stropping, ma la semantica differisce: i caratteri di sottolineatura fanno parte del valore dellidentificatore, piuttosto che essere citati caratteri (come lo stropping): il valore di __foo è __foo (che è riservato), non foo (ma in uno spazio dei nomi diverso).

Commenti

  • " cerca di abbreviare i nomi se possibile " Usa un IDE con completamento automatico, quindi i nomi delle tue funzioni possono essere lunghi e descrittivi quanto ti servono per digitare poi una volta.
  • @Joel terribile consiglio. Non tutti useranno il tuo stesso IDE.
  • @James Non ' non ne hanno bisogno, possono semplicemente usare qualsiasi IDE decente. Quindi non ' devi sacrificare la chiarezza per la produttività.
  • Il termine IDE è diventato un po sottile ormai da qualche giorno. Tecnicamente Notepad ++ è un IDE perché puoi configurarlo per compilare ed eseguire il tuo progetto, ma ' è principalmente un editor di testo. E si completa automaticamente.

Risposta

Lunico vincolo in C è che non ci sono spazi dei nomi. Pertanto, devi trovare un modo per rendere la funzione rename() della tua libreria filesystem distinta dalla rename() funzione della tua libreria media . La solita soluzione è un prefisso, come: filesystem_rename() e media_rename().

Laltro consiglio generale è: resta coerente allinterno di un progetto o di un team. La leggibilità sarà migliorata.

Commenti

  • +1: Ciò è particolarmente vero per i simboli esportati in una libreria. " Mi dispiace, ma quella libreria del filesystem non è compatibile con quella libreria multimediale, perché entrambi hanno una funzione di rinomina esportata.

Risposta

SE STAI CERCANDO UN GLOBALMENTE FORMATO ACCETTATO

MISRA / JSF / AUTOSAR copre quasi il 100% di qualsiasi standard industriale per la denominazione e lorganizzazione del codice C / C ++. Il problema è che non saranno disponibili gratuitamente, ovvero ciascuna delle guide costa un po di soldi. So che il libro standard di codifica MISRA 2008 C / C ++ probabilmente costa circa 50 USD.

Puoi pensare a questi come riferimenti ad Harvard per la bibliografia e la lettura aggiuntiva quando scrivi un diario. Ho usato MISRA ed è un buon modo per nominare le tue funzioni e variabili e organizzarle per un uso corretto.

SE STAI CERCANDO QUALCOSA DI TEMPORANEO

I riferimenti che hai fornito per Python e Java sono a posto, immagino. Ho visto persone che adottano lo stile javadoc per commenti, nomi e organizzazione del codice. È un dato di fatto, nel mio ultimo progetto, ho dovuto scrivere codice C ++ in funzioni / nomi di variabili simili a Java. Due ragioni alla base di questo:

1) Apparentemente era più facile da seguire.

2) I requisiti del codice di produzione non toccavano il terreno degli standard di sistema software critici per la sicurezza.

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

4) Doxygen consentiva a Javadoc i commenti sytle. In quel momento, stavamo usando doxygen per generare la documentazione per i ragazzi della produzione.

Molti programmatori saranno oppositori di questo, ma personalmente ritengo che non ci sia niente di sbagliato nelladottare funzioni / variabili in stile javadoc in C / C ++. SÌ, Certamente, le pratiche di organizzazione del controllo del flusso, della sicurezza dei thread, ecc. Devono essere affrontate a prescindere. Tuttavia, non sono un candidato qui. Inoltre, non so quanto siano rigidi i requisiti del formato del codice di produzione. Senza dirottarli in unarea fuori tema, ti suggerisco di rivedere i tuoi requisiti, scoprire quanto sei dipendente da una specifica convenzione di denominazione e scegliere una soluzione menzionata nelle mie e altre “risposte

Spero che questo abbia aiutato !?

Commenti

  • In realtà lo stavo chiedendo per codici C personali . Ma ' ricorderò il tuo suggerimento.
  • @AseemBansal Personale o professionale, quelli sono buoni da imparare e anche da inserire nel tuo CV 🙂 … . Dipende da te.

Risposta

Poche cose importanti da considerare durante la denominazione sarebbero:

  1. Controlla il tipo di actionObject o ObjectAction. (Object Not for C. Ma in generale quando vai ad altri linguaggi Object Oriented) Questo dovrebbe aiutare

  2. Il riposo sarebbe COSTANTE, breve e sicuramente descrittivo.

  3. Inoltre, un unico scopo di ogni variabile e funzione definita, ad esempio: se si tratta di memorizzare un valore temporaneamente, chiamalo come nTempVal per int
  4. Le variabili dovrebbero essere un nome e i metodi dovrebbero essere verbo.

Commenti

  • La notazione ungherese (anteponendo a una variabile lettere che ne indicano il tipo) non porta al dolore. Fortunatamente è perlopiù passato di moda.
  • @StevenBurnap Era solo curioso di sapere perché si evita il formato ungherese? Credo che ' sia quello che ci hanno insegnato a scuola e ho visto codice del genere anche in alcuni luoghi di lavoro. Quale consiglieresti se non ungherese. Grazie
  • La migliore convenzione di denominazione è solo quella usata in modo coerente, con nomi chiari e descrittivi, idealmente mantenuti relativamente brevi senza abbreviazioni eccessive ed evitando prefissi ridondanti. La notazione ungherese ha poca utilità effettiva, rende il codice più difficile da leggere e rende più difficile cambiare i tipi.
  • Ecco una descrizione dellintento originale e labominio che la notazione ungherese è diventata: joelonsoftware.com/articles/Wrong.html
  • @Residuum Quello era un buon collegamento. Ha aiutato molto. Apprezzalo.

Risposta

La maggior parte delle risposte sono buone, ma vorrei dire alcune cose sulla denominazione convenzioni per le librerie e i file inclusi, simili allutilizzo di spazi dei nomi in altri linguaggi come C ++ o Java:

Se costruisci una libreria, trova un prefisso comune per i tuoi simboli esportati, cioè funzioni globali, typedef e variabili. Ciò eviterà conflitti con altre librerie e identificherà le funzioni come provenienti dalla tua. Questo è un po di app notazioni ungheresi.

Forse vai ancora oltre e raggruppa i tuoi 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 “spazi dei nomi” per le diverse interfacce: chiamare una funzione curl_easy_ * su un handle curl_multi_ * ora sembra sbagliato, vedere i nomi delle funzioni in http://curl.haxx.se/libcurl/c/

Mantenendo le regole per i simboli esportati, dovresti utilizzare quelle per le funzioni statiche in #include ed files: prova a trovare un prefisso comune per queste funzioni. Forse hai funzioni di utilità di stringa statica in un file chiamato “my_string”? Prefissa tutte queste funzioni con my_string_ *.

Commenti

  • Per simboli esportati intendi variabili globali, funzioni, typedef ecc. Se ho ragione. Puoi spiegare la parte relativa al raggruppamento dei simboli esportati? Pensavo lo avessi già spiegato nel paragrafo precedente. Che cosa hai aggiunto nel 3 ° paragrafo?

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *