Quali sono le convenzioni di denominazione più comuni in C?


126

Quali sono le convenzioni di denominazione comunemente usate in C? So che ce ne sono almeno due:

  1. GNU / linux / K&R con lower_case_functions
  2. ? nome ? con funzioni UpperCaseFoo

Sto parlando di C solo qui. La maggior parte dei nostri progetti sono piccoli sistemi embedded in cui utilizziamo C.

Ecco quello che intendo utilizzare per il mio prossimo progetto:


C Convenzione sulla denominazione

Struct              TitleCase
Struct Members      lower_case or lowerCase

Enum                ETitleCase
Enum Members        ALL_CAPS or lowerCase

Public functions    pfx_TitleCase (pfx = two or three letter module prefix)
Private functions   TitleCase
Trivial variables   i,x,n,f etc...
Local variables     lower_case or lowerCase
Global variables    g_lowerCase or g_lower_case (searchable by g_ prefix)

7
Non forzerei un prefisso "g_" sulle variabili globali; Vorrei applicare nomi significativi (quindi client_locale e non cl_lc come nome di variabile globale). Il classico C non usa la custodia del cammello; Ho scritto codice in camel-case in C, e sembra strano (quindi non lo faccio più così). Detto questo, non è sbagliato e la coerenza è più importante della convenzione utilizzata. Evita i typedef che incapsulano i puntatori alla struttura; considera lo standard C - 'FILE *' è scritto così, non FILE_PTR.
Jonathan Leffler

2
@ Jonathan Leffler, cosa c'è di sbagliato in g_ per indicare i globali? Nei sistemi embedded ho avuto problemi in precedenza in cui era difficile rintracciare le dipendenze tra moduli tramite le variabili globali e g_somevar extern. Personalmente penso che sia generalmente una cattiva idea, ma questo genere di cose di solito viene fatto per motivi di prestazioni. Ad esempio, un flag globale impostato da un interrupt che indica che i dati sono pronti.
JeffV

2
Per quello che vale, questa convenzione di denominazione è stata per lo più strappata dalle convenzioni API di PalmOS. Inoltre, è simile alla convenzione usata nel libro di O'Reilly: "Programmazione di sistemi integrati con C e strumenti di sviluppo GNU". Personalmente, mi piace il TitleCase nei nomi delle funzioni. Stavo pensando di andare con lowerCamelCase nelle funzioni di collegamento interno (che ho chiamato private nella mia domanda).
JeffV

3
@ Chris Lutz, sono d'accordo, di tutto cuore. Ove possibile, i vars devono essere mantenuti nel campo più ristretto. Si noti che in realtà ci sono tre ambiti di cui stiamo discutendo: locale a una funzione, locale a un modulo (nessun collegamento esterno alla variabile) e globali con collegamento esterno. È comune avere variabili "globali per un modulo" nei sistemi embedded. Pertanto, è necessario prestare attenzione a identificare le globali con collegamento esterno in modo che possano essere ridotte al minimo e le interazioni del modulo comprese. È qui che il prefisso "g_" è utile.
JeffV

46
Mi piace anteporre alle variabili globali //.
plafer

Risposte:


128

La cosa più importante qui è la coerenza. Detto questo, seguo la convenzione di codifica GTK +, che può essere riassunta come segue:

  1. Tutte le macro e le costanti in maiuscolo: MAX_BUFFER_SIZE, TRACKING_ID_PREFIX.
  2. Nomi di strutture e typedef in camelcase: GtkWidget, TrackingOrder.
  3. Funzioni che operano su struct: classic C style: gtk_widget_show(), tracking_order_process().
  4. Puntatori: niente di speciale qui: GtkWidget *foo, TrackingOrder *bar.
  5. Variabili globali: semplicemente non utilizzare variabili globali. Sono malvagi.
  6. Funzioni che ci sono, ma non dovrebbero essere chiamate direttamente, o che hanno usi oscuri, o qualsiasi altra cosa: uno o più trattini bassi all'inizio: _refrobnicate_data_tables(), _destroy_cache().

13
Al punto sei preferisco usare statice saltare il prefisso del modulo, quindi se gtk_widget_show()fosse una funzione con ambito di file diventerebbe semplicemente widget_show()con la classe di archiviazione statica aggiunta.
August Karlstrom

27
Nota aggiuntiva sul punto 6: lo standard C ha alcune regole sulla prenotazione dei nomi che iniziano con _per l'implementazione e l'uso futuro. Ci sono alcune eccezioni ai nomi che iniziano con _ma secondo me non vale la pena memorizzarli. Una regola sicura da seguire è quella di non usare mai nomi che iniziano con _nel codice. Voce
jw013

5
# 2 è più specificamente il caso del cammello superiore o il caso pascal . Il caso del cammello o il minuscolo del cammello usa il minuscolo sulla prima lettera.
Clint Pachl

9
E le variabili locali composte da più parole? my_var o myVar?
Dean Gurvitz

4
Global variables: just don't use global variables. They are evil.- a meno che tu non stia lavorando su un progetto incorporato e tu abbia 1024 byte di RAM e 8MHz CPU.
Kamil

30

I "puntatori a struttura" non sono entità che richiedono una clausola di convenzione di denominazione per coprirli. Sono solo struct WhatEver *. NON nascondere il fatto che c'è un puntatore coinvolto in un typedef intelligente e "ovvio". Non serve a nulla, è più lungo da digitare e distrugge l'equilibrio tra dichiarazione e accesso.


29
+1 per le cose "non nascondere i puntatori" - anche se questa risposta non affronta gran parte del resto della domanda (ancora).
Jonathan Leffler

1
@unwind, tendo ad essere d'accordo. Tuttavia, a volte un puntatore non è destinato a essere dereferenziato dall'esterno ed è più un handle per il consumatore che un puntatore effettivo a una struttura che useranno. Questo è quello per cui ho lasciato il TitleCasePtr. typedef struct {fields} MyStruct, * MyStructPtr;
JeffV

Sto rimuovendo TitleCasePtr, distrae dalla domanda reale.
JeffV

1
-1 da me poiché una dichiarazione del tipo di puntatore riduce il disordine, specialmente nelle firme delle funzioni e lo "squilibrio" tra dichiarazione e accesso si manifesta solo nel file di implementazione - il client non (non dovrebbe) accedere direttamente ai membri del campo.
August Karlstrom

1
@AugustKarlstrom Fine. Non capisco cosa sia così "solo" nel file di implementazione, non è anche questo codice? Non ho interpretato la domanda riguardante solo nomi "esterni". Tutto il codice è "implementazione" a un certo livello.
rilassarsi il

17

Bene, in primo luogo C non ha funzioni pubbliche / private / virtuali. Questo è C ++ e ha convenzioni diverse. In C in genere hai:

  • Costanti in ALL_CAPS
  • Sottolineature per delimitare le parole nelle strutture o nei nomi delle funzioni, non vedi quasi mai il caso del cammello in C;
  • i valori di struct, typedef, unions, members (di unions e struct) e enum sono tipicamente in minuscolo (nella mia esperienza) piuttosto che nella convenzione C ++ / Java / C # / ecc di rendere la prima lettera maiuscola ma immagino che sia possibile in Anche C.

Il C ++ è più complesso. Ho visto un vero mix qui. Caso cammello per nomi di classe o minuscolo + trattini bassi (il caso cammello è più comune nella mia esperienza). Le strutture sono usate raramente (e in genere perché una libreria le richiede, altrimenti useresti le classi).


@cletus, me ne rendo conto. Per privato intendo funzioni che non sono esposte esternamente nell'intestazione del modulo e non sono destinate ad essere utilizzate da codice esterno al modulo. Pubblico sarebbe le funzioni API del modulo destinate ad essere utilizzate esternamente.
JeffV

3
Potreste considerare le funzioni statiche come private; la domanda non parla di virtuale. Ma +1 per "vedere raramente la custodia dei cammelli in C".
Jonathan Leffler

2
Penso che Jeff intendesse external linkageper "funzioni pubbliche" e internal linkageper "funzioni private".
pmg

1
Ho visto costanti che iniziano con ak così come in: kBufferSize. Non sono sicuro da dove provenga.
JeffV

2
ALL_CAPSviene spesso utilizzato anche per i valori enum.
caf

14

Sai, mi piace mantenerlo semplice, ma chiaro ... Quindi ecco cosa uso, in C:

  • Variabili banali : i,n,c(. Solo una lettera Se una lettera non è chiaro, poi ne fanno una variabile locale), ecc ...
  • Variabili locali :lowerCamelCase
  • Variabili globali :g_lowerCamelCase
  • Variabili costanti :ALL_CAPS
  • Variabili puntatore : aggiungi p_a al prefisso. Per le variabili globali sarebbe gp_var, per le variabili locali, per le variabili p_varconst p_VAR. Se vengono utilizzati puntatori lontani, utilizzare fp_invece di p_.
  • Structs : ModuleCamelCase(Modulo = nome completo del modulo o un'abbreviazione di 2-3 lettere, ma ancora in CamelCase.)
  • Variabili membro Struct :lowerCamelCase
  • Enumerazioni :ModuleCamelCase
  • Valori enumerativi :ALL_CAPS
  • Funzioni pubbliche :ModuleCamelCase
  • Funzioni private :CamelCase
  • Macro :CamelCase

Digito i miei struct, ma uso lo stesso nome sia per il tag che per il typedef. Il tag non è pensato per essere usato comunemente. Invece è preferibile usare il typedef. Dichiaro anche in avanti il ​​typedef nell'intestazione del modulo pubblico per l'incapsulamento e in modo da poter utilizzare il nome typedef nella definizione.

struct Esempio completo :

typdef struct TheName TheName;
struct TheName{
    int var;
    TheName *p_link;
};

Non so nulla del framework qt, ma puoi scrivere il tuo codice in qualsiasi formato di stile desideri. Niente ti impedisce di farlo, per quanto ne so.
SeanRamey

10

Codificando in C #, Java, C, C ++ e Object C allo stesso tempo, ho adottato una convenzione di denominazione molto semplice e chiara per semplificarmi la vita.

Prima di tutto, si basa sulla potenza dei moderni IDE (come eclipse, Xcode ...), con la possibilità di ottenere informazioni rapide passando con il mouse o con ctrl click ... Accettandolo, ho soppresso l'uso di qualsiasi prefisso, suffisso e altri marcatori che sono semplicemente dati dall'IDE.

Quindi, la convenzione:

  • Qualsiasi nome DEVE essere una frase leggibile che spieghi quello che hai. Come "questa è la mia convenzione".
  • Quindi, 4 metodi per ottenere una convenzione da una frase:
    1. THIS_IS_MY_CONVENTION per macro, membri enum
    2. ThisIsMyConvention per nome file, nome oggetto (classe, struct, enum, union ...), nome funzione, nome metodo, typedef
    3. this_is_my_convention variabili globali e locali,
      parametri, struttura ed elementi di unione
    4. thisismyconvention [opzionale] variabili molto locali e temporanee (come un indice di ciclo for ())

E questo è tutto.

class MyClass {
    enum TheEnumeration {
        FIRST_ELEMENT,
        SECOND_ELEMENT,
    }

    int class_variable;

    int MyMethod(int first_param, int second_parameter) {
        int local_variable;
        TheEnumeration local_enum;
        for(int myindex=0, myindex<class_variable, myindex++) {
             localEnum = FIRST_ELEMENT;
        }
    }
}

8

Consiglierei di non mescolare il caso del cammello e la separazione del carattere di sottolineatura (come hai proposto per i membri della struttura). Questo è confusionario. Penseresti, hey l'ho fatto get_lengthquindi probabilmente avrei dovuto make_subsete poi scoprirai che in realtà è makeSubset. Usa il principio del minimo stupore e sii coerente.

Trovo CamelCase utile per digitare nomi, come struct, typedef ed enumerazioni. Ma questo è tutto. Per tutto il resto (nomi di funzioni, nomi di membri della struttura, ecc.) Utilizzo underscore_separation.


1
Sì, l'aspetto principale di qualsiasi convenzione di denominazione è la prevedibilità e la coerenza. Inoltre, poiché la libreria C stessa utilizza tutte le lettere minuscole con _ per la spaziatura, consiglierei di usarlo solo per non dover gestire 2 diverse convenzioni di denominazione in un progetto (supponendo che non si scriva un wrapper attorno a libc per creare è conforme alla tua denominazione .. ma è disgustoso)
Earlz

Utilizza anche typedef con una " t" alla fine, ma non vedo nessuno che lo consigli. In effetti, la libreria standard è persino incoerente: div_t (stdlib.h) è una struttura e così è tm (time.h). Inoltre, dai un'occhiata ai membri della struttura tm, hanno tutti il ​​prefisso tm che sembra inutile e brutto (IMO).
JeffV

1
"Trovo CamelCase utile per digitare i nomi ..." Se lo inizi in maiuscolo, in realtà è PascalCase.
Tagc

7

Eccone uno (apparentemente) raro, che ho trovato utile: nome del modulo in CamelCase, quindi un trattino basso, quindi il nome della funzione o dell'ambito del file in CamelCase. Quindi per esempio:

Bluetooth_Init()
CommsHub_Update()
Serial_TxBuffer[]

2
Non così insolito, ma molto utile.
chux - Ripristina Monica il

3

Sono confuso da una cosa: stai pianificando di creare una nuova convenzione di denominazione per un nuovo progetto. In genere dovresti avere una convenzione di denominazione che sia a livello di azienda o di team. Se hai già progetti che hanno una qualsiasi forma di convenzione di denominazione, non dovresti modificare la convenzione per un nuovo progetto. Se la convenzione di cui sopra è solo la codificazione delle tue pratiche esistenti, allora sei d'oro. Quanto più differisce dagli standard de facto esistenti, tanto più difficile sarà ottenere la condivisione mentale nel nuovo standard.

L'unico suggerimento che vorrei aggiungere è che mi piace _t alla fine dei tipi nello stile di uint32_t e size_t. È molto C-ish per me, anche se alcuni potrebbero lamentarsi che è solo ungherese "al contrario".


3
Ebbene, le convenzioni qui sono dappertutto e incoerenti, motivo per cui intendo documentarne una. Inoltre, è per questo che lo chiedo. Per vedere qual è il consenso della comunità.
JeffV

Capisco quel dolore. Ma ci deve essere un sottoinsieme delle convenzioni esistenti che è più popolare. Dovresti iniziare da lì e non da una pagina web Internet a caso. Inoltre dovresti chiedere agli altri tuoi sviluppatori cosa considererebbero buono.
jmucchiello

7
Credo che i nomi dei tipi che terminano con _t siano riservati dallo standard POSIX.
caf

4
I nomi che finiscono con _t sono riservati. Vedi gnu.org/software/libc/manual/html_node/Reserved-Names.html , "I nomi che terminano con '_t' sono riservati per nomi di tipi aggiuntivi".
Étienne

2

Dovresti anche pensare all'ordine delle parole per rendere più facile il completamento automatico del nome .

Una buona pratica: nome della libreria + nome del modulo + azione + oggetto

Se una parte non è rilevante, saltala, ma devono essere sempre presentati almeno un nome di modulo e un'azione.

Esempi:

  • Nome funzione: os_task_set_prio, list_get_size,avg_get
  • definire (qui di solito nessuna parte di azione ):OS_TASK_PRIO_MAX

0

Potrebbero essercene molti, principalmente IDE dettano alcune tendenze e anche le convenzioni C ++ stanno spingendo. Per C comunemente:

  • UNDERSCORED_UPPER_CASE (definizioni macro, costanti, membri enum)
  • underscored_lower_case (variabili, funzioni)
  • CamelCase (tipi personalizzati: structs, enums, unions)
  • uncappedCamelCase (stile Java oppa)
  • UnderScored_CamelCase (variabili, funzioni sotto il tipo di spazi dei nomi)

La notazione ungherese per le variabili globali va bene ma non per i tipi. E anche per nomi banali, usa almeno due caratteri.


-1

Penso che possano aiutare per i principianti: convenzione di denominazione delle variabili in c

  1. Devi usare il carattere alfabetico (az, AZ), la cifra (0-9) e il punteggio inferiore (_). Non è consentito l'uso di caratteri speciali come:%, $, #, @ ecc. Quindi, puoi usare user_name come variabile ma non puoi usare user & name .
  2. Non è possibile utilizzare spazi bianchi tra le parole. Quindi, puoi usare nome_utente o nome utente o nome utente come variabile ma non puoi usare il nome utente .
  3. Impossibile iniziare a denominare con cifra. Quindi, puoi usare user1 o user2 come variabile ma non puoi usare 1user .
  4. È un linguaggio case sensitive. Le maiuscole e le minuscole sono significative. Se usi una variabile come username, non puoi usare USERNAME o Username per uso padre.
  5. Non è possibile utilizzare alcuna parola chiave (char, int, if, for, while ecc.) Per la dichiarazione delle variabili.
  6. Lo standard ANSI riconosce una lunghezza di 31 caratteri per un nome di variabile

Questo post mira chiaramente a discutere le convenzioni di denominazione , non le restrizioni . Ciò che hai elencato sono cose che non puoi nemmeno fare perché si tratta di errori di sintassi.
Inseguimento l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.