Was sind die häufigsten Namenskonventionen in C?


124

Welche Namenskonventionen werden üblicherweise in C verwendet? Ich weiß, dass es mindestens zwei gibt:

  1. GNU / linux / K & R mit Kleinbuchstabenfunktionen
  2. ? Name ? mit UpperCaseFoo-Funktionen

Ich spreche nur hier von C. Die meisten unserer Projekte sind kleine eingebettete Systeme, in denen wir C verwenden.

Hier ist die, die ich für mein nächstes Projekt verwenden möchte:


C Namenskonvention

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
Ich würde globalen Variablen kein Präfix 'g_' aufzwingen. Ich würde aussagekräftige Namen erzwingen (also client_locale und nicht cl_lc als globalen Variablennamen). Classic C verwendet kein Kamelgehäuse. Ich habe Code in Camel-Case in C geschrieben und es sieht komisch aus (also mache ich das nicht mehr so). Das heißt, es ist nicht falsch - und Konsistenz ist wichtiger als die verwendete Konvention. Vermeiden Sie Typedefs, die Strukturzeiger kapseln. Betrachten Sie den C-Standard - 'FILE *' wird also geschrieben, nicht FILE_PTR.
Jonathan Leffler

2
@ Jonathan Leffler, was ist falsch an g_, um Globale zu bezeichnen? In eingebetteten Systemen hatte ich zuvor Probleme, bei denen es schwierig war, Abhängigkeiten zwischen Modulen über globale Variablen und externes g_somevar aufzuspüren. Ich persönlich halte es im Allgemeinen für eine schlechte Idee, aber solche Dinge werden normalerweise aus Leistungsgründen erledigt. Zum Beispiel ein globales Flag, das von einem Interrupt gesetzt wird, der angibt, dass die Daten bereit sind.
JeffV

2
Für das, was es wert ist, wurde diese Namenskonvention größtenteils aus PalmOS API-Konventionen herausgerissen. Es ähnelt auch der Konvention in O'Reillys Buch "Programmieren eingebetteter Systeme mit C- und GNU-Entwicklungstools". Persönlich mag ich den TitleCase in Funktionsnamen. Ich dachte daran, mit LowerCamelCase in internen Verknüpfungsfunktionen zu arbeiten (die ich in meiner Frage als privat bezeichnet habe).
JeffV

3
@ Chris Lutz, ich stimme von ganzem Herzen zu. Wo immer möglich, sind Vars auf engstem Raum zu halten. Beachten Sie, dass es tatsächlich drei Bereiche gibt, die wir diskutieren: lokal für eine Funktion, lokal für ein Modul (keine externe Verknüpfung mit der Variablen) und die globalen Bereiche mit externer Verknüpfung. In eingebetteten Systemen ist es üblich, Variablen "global zu einem Modul" zu haben. Daher muss darauf geachtet werden, die Globals mit externer Verknüpfung zu identifizieren, damit sie auf ein Minimum beschränkt und die Modulinteraktionen verstanden werden können. Hier ist das Präfix "g_" hilfreich.
JeffV

46
Ich möchte globalen Variablen // voranstellen.
Plafer

Antworten:


126

Das Wichtigste dabei ist die Konsistenz. Trotzdem folge ich der GTK + -Codierungskonvention, die wie folgt zusammengefasst werden kann:

  1. Alle Makros und Konstanten in Großbuchstaben: MAX_BUFFER_SIZE, TRACKING_ID_PREFIX.
  2. Strukturnamen und Typedefs in camelcase: GtkWidget, TrackingOrder.
  3. Funktionen, die mit Strukturen arbeiten: klassischer C-Stil: gtk_widget_show(), tracking_order_process().
  4. Zeiger: hier nichts Besonderes: GtkWidget *foo, TrackingOrder *bar.
  5. Globale Variablen: Verwenden Sie einfach keine globalen Variablen. Sie sind böse.
  6. Funktionen, die vorhanden sind, aber nicht direkt aufgerufen werden sollten oder unklare Verwendungszwecke haben oder was auch immer: ein oder mehrere Unterstriche am Anfang: _refrobnicate_data_tables(), _destroy_cache().

13
In Punkt 6 bevorzuge ich es, das Modulpräfix zu verwenden staticund zu überspringen. Wenn also gtk_widget_show()eine Funktion mit Dateibereich wäre, würde sie einfach widget_show()mit einer statischen Speicherklasse hinzugefügt.
August Karlstrom

26
Zusätzlicher Hinweis zu Punkt 6: Der C-Standard enthält einige Regeln zum Reservieren von Namen, die _für die Implementierung und zukünftige Verwendung beginnen. Es gibt einige Ausnahmen zu Namen, die mit beginnen, _aber meiner Meinung nach lohnt es sich nicht, sie auswendig zu lernen. Eine sichere Regel ist, niemals Namen zu verwenden, die _in Ihrem Code beginnen. Relevanter C FAQ Eintrag: c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=decl#namespace
jw013

5
# 2 ist genauer gesagt der obere Kamel- oder Pascalfall . Kamel- oder Kleinkamel verwendet Kleinbuchstaben für den ersten Buchstaben.
Clint Pachl

9
Was ist mit lokalen Mehrwortvariablen? my_var oder myVar?
Dean Gurvitz

4
Global variables: just don't use global variables. They are evil.- Es sei denn, Sie arbeiten an einem eingebetteten Projekt und verfügen über 1024 Byte RAM und eine 8-MHz-CPU.
Kamil

30

"Strukturzeiger" sind keine Entitäten, die eine Namenskonventionsklausel benötigen, um sie abzudecken. Sie sind einfach struct WhatEver *. Verstecken Sie nicht die Tatsache, dass es sich um einen Zeiger handelt, der mit einem cleveren und "offensichtlichen" Typedef verbunden ist. Es hat keinen Zweck, ist länger zu tippen und zerstört das Gleichgewicht zwischen Deklaration und Zugriff.


29
+1 für das Zeug "Zeiger nicht verstecken" - obwohl diese Antwort (noch) nicht viel vom Rest der Frage anspricht.
Jonathan Leffler

1
@unwind, ich stimme eher zu. Manchmal soll ein Zeiger jedoch nicht extern dereferenziert werden, und er ist für den Verbraucher eher ein Handle als ein tatsächlicher Zeiger auf eine Struktur, die er verwenden wird. Dafür habe ich den TitleCasePtr verlassen. typedef struct {fields} MyStruct, * MyStructPtr;
JeffV

Ich entferne den TitleCasePtr, er lenkt von der eigentlichen Frage ab.
JeffV

1
-1 von mir, da eine Zeigertypdeklaration die Unordnung verringert, insbesondere bei Funktionssignaturen, und das "Ungleichgewicht" zwischen Deklaration und Zugriff nur in der Implementierungsdatei angezeigt wird - der Client greift nicht (nicht) direkt auf die Feldmitglieder zu.
August Karlstrom

1
@ AugustKarlstrom Fein. Ich verstehe nicht, was so "nur" an der Implementierungsdatei ist, ist das nicht auch Code? Ich habe die Frage nicht nur als "externe" Namen interpretiert. Der gesamte Code ist auf einer bestimmten Ebene "Implementierung".
Entspannen Sie

17

Erstens hat C keine öffentlichen / privaten / virtuellen Funktionen. Das ist C ++ und es gibt verschiedene Konventionen. In C haben Sie normalerweise:

  • Konstanten in ALL_CAPS
  • Unterstreichungen, um Wörter in Strukturen oder Funktionsnamen abzugrenzen, sehen Sie in C kaum einen Kamelfall;
  • Strukturen, Typedefs, Gewerkschaften, Mitglieder (von Gewerkschaften und Strukturen) und Aufzählungswerte werden (meiner Erfahrung nach) normalerweise in Kleinbuchstaben geschrieben und nicht in der C ++ / Java / C # / etc-Konvention, den ersten Buchstaben zu einem Großbuchstaben zu machen, aber ich denke, es ist möglich in C auch.

C ++ ist komplexer. Ich habe hier eine echte Mischung gesehen. Kamelbuchstaben für Klassennamen oder Kleinbuchstaben + Unterstriche (Kamelbuchstaben sind meiner Erfahrung nach häufiger). Strukturen werden selten verwendet (und normalerweise, weil eine Bibliothek sie benötigt, andernfalls würden Sie Klassen verwenden).


@cletus, das merke ich. Mit privat meine ich Funktionen, die nicht extern im Modulheader verfügbar gemacht werden und nicht für Code außerhalb des Moduls verwendet werden sollen. Öffentlich wären Modul-API-Funktionen, die extern verwendet werden sollen.
JeffV

3
Sie können statische Funktionen als privat betrachten. Die Frage erwähnt nicht virtuell. Aber +1 für 'Kamelfall in C selten sehen'.
Jonathan Leffler

2
Ich denke, Jeff meinte external linkagefür "öffentliche Funktionen" und internal linkagefür "private Funktionen".
PMG

1
Ich habe Konstanten gesehen, die sowohl mit ak als auch in: kBufferSize beginnen. Ich bin mir nicht sicher, woher das kommt.
JeffV

2
ALL_CAPSwird oft auch für Enum-Werte verwendet.
Café

14

Weißt du, ich halte es gerne einfach, aber klar ... Also hier ist, was ich in C verwende:

  • Triviale Variablen : i,n,cusw. (Nur ein Buchstabe. Wenn ein Buchstabe nicht klar ist, machen Sie ihn zu einer lokalen Variablen.)
  • Lokale Variablen :lowerCamelCase
  • Globale Variablen :g_lowerCamelCase
  • Konstantenvariablen :ALL_CAPS
  • Zeigervariablen : Fügen Sie a hinzup_ dem Präfix ein hinzu. Für globale Variablen wäre es gp_varfür lokale Variablen p_varfür const-Variablen p_VAR. Wenn Fernzeiger verwendet werden, verwenden Sie ein fp_anstelle von p_.
  • Strukturen : ModuleCamelCase(Modul = vollständiger Modulname oder Abkürzung mit 2-3 Buchstaben, aber immer noch in CamelCase.)
  • Strukturelementvariablen :lowerCamelCase
  • Aufzählungen :ModuleCamelCase
  • Enum-Werte :ALL_CAPS
  • Öffentliche Funktionen :ModuleCamelCase
  • Private Funktionen :CamelCase
  • Makros :CamelCase

Ich schreibe meine Strukturen, benutze aber den gleichen Namen für das Tag und das typedef. Das Tag ist nicht für die allgemeine Verwendung vorgesehen. Stattdessen ist es vorzuziehen, das typedef zu verwenden. Ich deklariere auch das typedef im öffentlichen Modul-Header zur Kapselung weiter, damit ich den typedef'd-Namen in der Definition verwenden kann.

Vollständiges struct Beispiel :

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

Ich weiß nichts über das qt-Framework, aber Sie können Ihren Code in jedem gewünschten Stilformat schreiben. Soweit ich weiß, hält dich nichts davon ab.
SeanRamey

10

Codierung in C #, Java, C, C ++ und Ziel C. habe ich eine sehr einfache und klare Namenskonvention eingeführt, um mein Leben zu vereinfachen.

Zuallererst stützt es sich auf die Leistungsfähigkeit moderner IDEs (wie Eclipse, Xcode ...) mit der Möglichkeit, schnelle Informationen durch Schweben oder Klicken bei gedrückter Strg-Taste zu erhalten. Als ich dies akzeptierte, unterdrückte ich die Verwendung von Präfixen und Suffixen und andere Marker, die einfach von der IDE gegeben werden.

Dann die Konvention:

  • Alle Namen MÜSSEN ein lesbarer Satz sein, der erklärt, was Sie haben. Wie "das ist meine Konvention".
  • Dann 4 Methoden, um eine Konvention aus einem Satz herauszuholen:
    1. THIS_IS_MY_CONVENTION für Makros, Enum-Mitglieder
    2. ThisIsMyConvention für Dateiname, Objektname (Klasse, Struktur, Aufzählung, Union ...), Funktionsname, Methodenname, typedef
    3. this_is_my_convention globale und lokale Variablen,
      Parameter, Struktur- und Vereinigungselemente
    4. thisismyconvention [optional] sehr lokale und temporäre Variablen (wie ein for () - Schleifenindex)

Und das ist es.

Es gibt

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

Ich würde empfehlen, Kamelfall und Unterstrich nicht zu mischen (wie Sie es für Strukturmitglieder vorgeschlagen haben). Das ist verwirrend. Sie würden denken, hey ich habe, get_lengthalso sollte ich wahrscheinlich haben make_subsetund dann finden Sie heraus, dass es tatsächlich ist makeSubset. Verwenden Sie das Prinzip des geringsten Erstaunens und seien Sie konsequent.

Ich finde CamelCase nützlich, um Namen wie Strukturen, Typedefs und Enums einzugeben. Das ist aber alles. Für den Rest (Funktionsnamen, Namen der Strukturelemente usw.) verwende ich underscore_separation.


1
Ja, die Hauptsache bei jeder Namenskonvention ist Vorhersehbarkeit und Konsistenz. Da die C-Bibliothek selbst alle Kleinbuchstaben mit _ als Abstand verwendet, würde ich empfehlen, diese zu verwenden, damit Sie sich nicht mit zwei verschiedenen Namenskonventionen in einem Projekt befassen müssen (vorausgesetzt, Sie schreiben keinen Wrapper um libc, um sie zu erstellen es entspricht Ihrer Benennung .. aber das ist brutto)
Earlz

Es werden auch typedefs mit einem " t" am Ende verwendet, aber ich sehe niemanden, der dies empfiehlt. Tatsächlich ist die Standardbibliothek sogar inkonsistent: div_t (stdlib.h) ist eine Struktur und tm (time.h) auch. Schauen Sie sich auch die tm struct-Mitglieder an, denen alle tm vorangestellt sind, was sinnlos und hässlich erscheint (IMO).
JeffV

1
"Ich finde CamelCase nützlich, um Namen einzugeben ..." Wenn Sie es mit Großbuchstaben starten, ist es tatsächlich PascalCase.
Tagc

7

Hier ist eine (anscheinend) ungewöhnliche, die ich nützlich gefunden habe: Modulname in CamelCase, dann Unterstrich, dann Funktions- oder Dateibereichsname in CamelCase. Also zum Beispiel:

Bluetooth_Init()
CommsHub_Update()
Serial_TxBuffer[]

2
Nicht so ungewöhnlich, aber sehr nützlich.
chux

3

Eines verwirrt mich: Sie planen, eine neue Namenskonvention für ein neues Projekt zu erstellen. Im Allgemeinen sollten Sie eine Namenskonvention haben, die unternehmens- oder teamweit ist. Wenn Sie bereits Projekte mit einer Namenskonvention haben, sollten Sie die Konvention für ein neues Projekt nicht ändern. Wenn die obige Konvention nur eine Kodifizierung Ihrer bestehenden Praktiken ist, dann sind Sie golden. Je mehr es sich von bestehenden de facto unterscheidet Standards schwieriger wird es, sich über den neuen Standard Gedanken zu machen.

Der einzige Vorschlag, den ich hinzufügen möchte, ist, dass ich _t am Ende von Typen im Stil von uint32_t und size_t mag. Es ist sehr C-ish für mich, obwohl einige sich beschweren könnten, dass es nur "umgekehrt" ungarisch ist.


3
Nun, die Konventionen hier sind allgegenwärtig und inkonsistent, weshalb ich mich daran mache, eine zu dokumentieren. Deshalb frage ich auch. Um zu sehen, was der Konsens der Gemeinschaft ist.
JeffV

Ich verstehe diesen Schmerz. Es muss jedoch eine Teilmenge Ihrer vorhandenen Konventionen geben, die am beliebtesten ist. Sie sollten dort beginnen und nicht auf einer zufälligen Internet-Webseite. Sie sollten auch Ihre anderen Entwickler fragen, was sie für gut halten würden.
jmucchiello

7
Ich glaube, Typnamen, die mit _t enden, sind vom POSIX-Standard reserviert.
Café

4
Namensendungen mit _t sind vorbehalten. Siehe gnu.org/software/libc/manual/html_node/Reserved-Names.html , "Namen, die mit '_t' enden, sind für zusätzliche Typnamen reserviert."
Étienne

2

Sie sollten auch über die Reihenfolge der Wörter nachdenken , um die automatische Namensvervollständigung durchzuführen vereinfachen.

Eine gute Vorgehensweise: Bibliotheksname + Modulname + Aktion + Betreff

Wenn ein Teil nicht relevant ist, überspringen Sie es einfach, aber es sollten immer mindestens ein Modulname und eine Aktion angezeigt werden.

Beispiele:

  • Funktionsname: os_task_set_prio, list_get_size,avg_get
  • definieren (hier normalerweise kein Aktionsteil ):OS_TASK_PRIO_MAX

0

Es könnte viele geben, hauptsächlich IDEs, die einige Trends diktieren, und auch C ++ - Konventionen drängen. Für C häufig:

  • UNDERSCORED_UPPER_CASE (Makrodefinitionen, Konstanten, Aufzählungselemente)
  • underscored_lower_case (Variablen, Funktionen)
  • CamelCase (benutzerdefinierte Typen: Strukturen, Aufzählungen, Gewerkschaften)
  • uncappedCamelCase (im Java-Stil)
  • UnderScored_CamelCase (Variablen, Funktionen unter Namespaces)

Die ungarische Notation für Globale ist in Ordnung, aber nicht für Typen. Und selbst für triviale Namen verwenden Sie bitte mindestens zwei Zeichen.


-1

Ich denke, diese können für Anfänger hilfreich sein: Namenskonvention von Variablen in c

  1. Sie müssen alphabetisches Zeichen (az, AZ), Ziffer (0-9) und Under Score (_) verwenden. Es ist nicht erlaubt, Sonderzeichen wie:%, $, #, @ usw. zu verwenden. Sie können also Benutzername als Variable verwenden, Benutzer & Name jedoch nicht .
  2. Leerzeichen zwischen Wörtern können nicht verwendet werden. Sie können also Benutzername oder Benutzername oder Benutzername als Variable verwenden, aber keinen Benutzernamen verwenden .
  3. Kann nicht mit der Ziffer benennen. Sie können also Benutzer1 oder Benutzer2 als Variable verwenden, 1user jedoch nicht .
  4. Es ist Groß- und Kleinschreibung. Groß- und Kleinbuchstaben sind von Bedeutung. Wenn Sie eine Variable wie Benutzername verwenden , können Sie weder USERNAME noch Benutzername verwenden für die Verwendung durch den Vater verwenden.
  5. Sie können kein Schlüsselwort verwenden (char, int, if, for, while usw.) für die Variablendeklaration verwenden.
  6. Der ANSI-Standard erkennt eine Länge von 31 Zeichen für einen Variablennamen

Dieser Beitrag zielt darauf ab , deutlich zu benennen zu diskutieren Konventionen , nicht Einschränkungen . Was Sie aufgelistet haben, können Sie nicht einmal tun, da es sich um Syntaxfehler handelt.
Chase
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.