Namenskonventionen für Variablen und Funktionen in C [closed]

12

Beim Codieren eines großen Projekts in CI ist ein Problem aufgetreten. Wenn ich weiterhin Code schreibe, wird es manchmal schwierig sein, den Code zu organisieren. Ich meine, dass die Benennung von Funktionen und Variablen für verschiedene Teile des Programms verwechselt zu sein scheint.

Ich überlegte, ob es nützliche Namenskonventionen gibt, die ich für C-Variablen und -Funktionen verwenden kann.

Die meisten Sprachen schlagen eine Namenskonvention vor. Aber für C ist das einzige, was ich bisher gelesen habe, dass die Namen für die Lesbarkeit des Codes beschreibend sein sollten.

BEARBEITEN:

Beispiele für einige Beispiele für vorgeschlagene Namenskonventionen:

Ich habe irgendwo weitere Namenskonventionen für Java gelesen, konnte mich aber nicht erinnern, wo.

Aseem Bansal
quelle
Nennen Sie einige Beispiele für Sprachen mit vorgeschlagenen Namenskonventionen. Und wo finden wir diese Namenskonventionen?
Philip
@Philip Hinzugefügt Beispiele
Aseem Bansal
1
Es sollte kein Problem mit Variablen geben, da Sie keine globalen Variablen verwenden. Und für Funktionsnamen: wenn der Name des Moduls ist order.c, können Sie die Funktionen nennen order_add(), order_del()und so weiter . Möglicherweise gibt es alte Systeme, die Ihnen mitteilen, dass der Name innerhalb der ersten 8 Zeichen eindeutig sein muss. Wenn Sie später versehentlich zu c ++ wechseln, werden Sie es lieben, order::add()und order::del()dann zu schreiben .
ott--

Antworten:

17

Wenn ich weiterhin Code schreibe, wird es manchmal schwierig sein, den Code zu organisieren.

Dies ist Ihr Problem: Richtige Organisation, und der Stil sollte leichter fließen.

Warten Sie nicht , um Ihren Code zu organisieren: Halten Sie Ihren Code organisiert, während Sie gehen. Obwohl die Sprache dies nicht für Sie erledigt, sollte der Code dennoch in Module mit geringer Kopplung und hoher Kohäsion organisiert sein.

Diese Module liefern dann natürlich einen Namensraum. Kürzen Sie den Modulnamen (falls er lang ist) und stellen Sie den Funktionsnamen das Modul voran, um Kollisionen zu vermeiden.

Auf der Ebene der einzelnen Identifikatoren sind dies ungefähr in aufsteigender Reihenfolge der Subjektivität:

  1. Wähle eine Konvention und bleibe dabei
    • zB function_like_this(struct TypeLikeThis variable)ist üblich
  2. Vermeiden Sie auf jeden Fall die ungarische Notation (sorry JNL)

    • es sei denn, Sie sind bereit, es wie ursprünglich beabsichtigt zu verwenden, was bedeutet, dass Simonyis Apps nicht die Version für schreckliche Systeme sind, sondern die Notation für Apps

      Warum? Ich könnte einen Aufsatz darüber schreiben, aber ich schlage stattdessen vor, dass Sie diesen Artikel von Joel Spolsky lesen und dann noch ein paar mehr suchen, wenn Sie interessiert sind. Unten finden Sie einen Link zu Simonyis Originalarbeit.

  3. Vermeiden Sie Zeigertypedefs, es sei denn, sie sind wirklich undurchsichtige Cookie-Typen - sie verwirren nur die Dinge

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

    Was meine ich mit einem undurchsichtigen Cookie-Typ ? Ich meine etwas, das in einem Modul (oder einer Bibliothek oder was auch immer) verwendet wird und an Client-Code weitergegeben werden muss, aber dieser Client-Code kann nicht direkt verwendet werden. Es wird einfach an die Bibliothek zurückgegeben.

    Beispielsweise kann eine Datenbankbibliothek eine Schnittstelle wie diese verfügbar machen

    /* 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);

    Jetzt ist der Kontext für den Client-Code undurchsichtig , da Sie nicht hineinsehen können. Sie geben es einfach an die Bibliothek zurück. So etwas FILEist auch undurchsichtig, und ein Integer-Dateideskriptor ist auch ein Cookie , ist aber nicht undurchsichtig.


Ein Hinweis zum Design

Ich habe den Ausdruck niedrige Kopplung und hohe Kohäsion oben ohne Erklärung verwendet, und ich fühle mich ein bisschen schlecht dabei. Sie können danach suchen und wahrscheinlich einige gute Ergebnisse finden, aber ich werde versuchen, es kurz anzusprechen (wieder könnte ich einen Aufsatz schreiben, aber ich werde versuchen, es nicht zu tun).

Die oben skizzierte DB-Bibliothek weist eine geringe Kopplung auf, da sie eine kleine Schnittstelle zur Außenwelt freigibt. Durch das Ausblenden der Implementierungsdetails (teilweise mit dem undurchsichtigen Cookie-Trick) wird verhindert, dass der Client-Code von diesen Details abhängt.

Anstelle des undurchsichtigen Cookies deklarieren wir die Kontextstruktur so, dass ihr Inhalt sichtbar ist. Dazu gehört auch ein Socket-Dateideskriptor für eine TCP-Verbindung zur Datenbank. Wenn wir anschließend die Implementierung ändern, um die Verwendung eines gemeinsam genutzten Speichersegments zu unterstützen, wenn die Datenbank auf demselben Computer ausgeführt wird, muss der Client neu kompiliert und nicht nur neu verknüpft werden. Noch schlimmer ist , könnte der Client gestartet mit dem Dateideskriptor, zum Beispiel rief setsockoptdie Standardpuffergröße zu ändern, und jetzt braucht es eine Codeänderung als auch. All diese Details sollten in unserem Modul verborgen sein, wo dies praktisch ist, und dies ergibt eine geringe Kopplung zwischen den Modulen.

Das Beispiel zeigt auch eine hohe Kohäsion , da sich alle Methoden im Modul auf dieselbe Aufgabe beziehen (DB-Zugriff). Dies bedeutet , dass nur der Code , dass Bedürfnisse über die Implementierungsdetails kennen (das heißt, die Inhalte unserer Online - Cookie) tatsächlich Zugang zu ihnen haben, das erleichtert das Debuggen.

Sie können auch feststellen, dass die Auswahl eines Präfixes für die Gruppierung dieser Funktionen durch ein einzelnes Anliegen vereinfacht wurde.

Es ist einfach zu sagen, dass dieses Beispiel gut ist (zumal es noch nicht vollständig ist), aber es hilft Ihnen nicht sofort. Der Trick besteht darin, beim Schreiben und Erweitern des Codes auf Funktionen zu achten, die ähnliche Aufgaben ausführen oder mit denselben Typen arbeiten (die möglicherweise Kandidaten für ihr eigenes Modul sind), und auch auf Funktionen, die viele separate Aufgaben ausführen, die nicht erforderlich sind. Es ist wirklich verwandt und könnte Kandidaten für eine Aufteilung sein.

Nutzlos
quelle
Kannst du mir helfen zu verstehen, warum Ungarisch gemieden wird? Ich bin nur neugierig, mehr darüber zu erfahren. :)
JNL
@JNL: Ein Kommentar ist zu kurz, um ihn richtig zu erklären. Ich schlage vor, dass Sie es als neue Frage posten.
Bart van Ingen Schenau
with low coupling and high cohesion. Was bedeutet das? Und erklären Sie bitte über undurchsichtige Cookie-Typen. Ich habe keine Ahnung was das heißt.
Aseem Bansal
Ich habe versucht, beide kurz anzusprechen, und bin ehrlich gesagt der Kürze halber gescheitert. Hoffentlich solltest du damit anfangen.
Nutzlos
Ich antworte nach ein paar Tagen. Das tut mir leid. Ich habe deine Beschreibung von gelesen low coupling and high cohesion. Es bedeutet also im Grunde, Dinge zu kapseln, wenn ich kann, und es sollte so geschehen, dass die Funktionen, die tatsächlich benötigt werden, Zugriff haben sollten. Einige Dinge gingen mir über den Kopf, aber ich glaube immer noch, dass ich deinen Standpunkt verstanden habe.
Aseem Bansal
5

Meiner Meinung nach sind 90% des Namensproblems gelöst, wenn Sie drei Dinge beachten: a) Machen Sie Ihre Variablen- und Funktionsnamen so aussagekräftig wie möglich, b) Seien Sie im gesamten Code konsistent (dh, wenn eine Funktion den Namen addNumbers hat, a Die zweite Funktion sollte multiplyNumbers heißen und nicht numbersMul) und c) versuchen, die Namen möglichst kurz zu machen, da wir sie eingeben müssen.

Wenn Sie sich jedoch andere Aspekte zu diesem Thema ansehen möchten, finden Sie auf der Wikipedia-Seite zu Namenskonventionen eine gute Liste von Dingen, die Sie beachten sollten. Es gibt auch einen Abschnitt zu C und C ++:

In C und C ++ werden Schlüsselwörter und Standardbibliothekskennungen meist in Kleinbuchstaben angegeben. In der C-Standardbibliothek sind abgekürzte Namen am häufigsten (z. B. isalnum für eine Funktion, mit der geprüft wird, ob ein Zeichen alphanumerisch ist), während in der C ++ - Standardbibliothek häufig ein Unterstrich als Worttrennzeichen verwendet wird (z. B. out_of_range). Bezeichner, die Makros darstellen, werden gemäß Konvention nur mit Großbuchstaben und Unterstrichen geschrieben (dies steht in vielen Programmiersprachen im Zusammenhang mit der Konvention, bei Konstanten ausschließlich Großbuchstaben zu verwenden). Namen, die einen doppelten Unterstrich enthalten oder mit einem Unterstrich und einem Großbuchstaben beginnen, sind für die Implementierung reserviert (Compiler, Standardbibliothek) und sollten nicht verwendet werden (z. B. reserved__ oder _Reserved). [5] [6] Dies ähnelt oberflächlich dem Stroppen, unterscheidet sich jedoch in der Semantik:

Daniel Scocco
quelle
3
Verwenden Sie eine IDE mit automatischer Vervollständigung, dann können Ihre Funktionsnamen so lang und beschreibend sein, wie sie sein müssen, da Sie sie nur einmal eingeben müssen.
Joel
1
@ Joel schrecklichen Rat. Nicht jeder wird dieselbe IDE verwenden wie Sie.
James
6
@James Müssen sie nicht, sie können einfach jede anständige IDE verwenden. Dann müssen Sie für die Produktivität nicht auf Klarheit verzichten.
Joel
Der Begriff IDE ist jetzt ein bisschen dünn gedehnt. Technisch gesehen ist Notepad ++ eine IDE, da Sie es so konfigurieren können, dass es Ihr Projekt kompiliert und ausführt, aber es ist hauptsächlich ein Texteditor. Und es wird automatisch vervollständigt.
Philip
5

Die einzige harte Einschränkung in C ist, dass es keine Namespaces gibt. Daher müssen Sie eine Möglichkeit finden, die rename()Funktion Ihrer Dateisystembibliothek von der rename()Funktion Ihrer Medienbibliothek zu unterscheiden . Die übliche Lösung ist ein Präfix wie: filesystem_rename()und media_rename().

Der andere allgemeine Rat lautet: Bleiben Sie innerhalb eines Projekts oder eines Teams konsequent. Die Lesbarkeit wird verbessert.

mouviciel
quelle
+1: Dies gilt insbesondere für exportierte Symbole in einer Bibliothek. "Es tut mir leid, aber diese Dateisystembibliothek passt nicht zu dieser Medienbibliothek, da beide eine exportierte Funktion haben, die umbenannt wird.
Residuum
2

WENN SIE NACH EINEM GLOBAL AKZEPTIERTEN FORMAT SUCHEN

MISRA / JSF / AUTOSAR deckt nahezu 100% aller Industriestandards für die Benennung und Organisation von C / C ++ - Code ab. Das Problem ist, dass sie nicht kostenlos erhältlich sind, dh jeder Reiseführer kostet etwas Geld. Ich weiß, dass MISRA 2008 C / C ++ - Codierungsstandardbuch wahrscheinlich ungefähr 50 USD kostet.

Sie können sich diese als die Harvard-Referenz für Bibliografie und zusätzliche Lektüre vorstellen, wenn Sie eine Zeitschrift schreiben. Ich habe MISRA verwendet und es ist eine gute Möglichkeit, Ihre Funktionen und Variablen zu benennen und sie für die ordnungsgemäße Verwendung zu organisieren.

WENN SIE NACH ETWAS VORÜBERGEHENDEM SUCHEN

Ich denke, die Referenzen, die Sie für Python und Java angegeben haben, sind in Ordnung. Ich habe Leute gesehen, die den Javadoc-Stil angenommen haben, um Code zu kommentieren, zu benennen und zu organisieren. Tatsächlich musste ich in meinem letzten Projekt C ++ - Code in Java-ähnlichen Funktionen / Variablennamen schreiben. Zwei Gründe dafür:

1) Es war anscheinend einfacher zu folgen.

2) Die Anforderungen an den Produktionscode haben den Grund für sicherheitskritische Software-Systemstandards nicht berührt.

3) Legacy-Code war (irgendwie) in diesem Format.

4) Doxygen erlaubte Javadoc-Kommentaren. Zu diesem Zeitpunkt verwendeten wir Sauerstoff, um die Dokumentation für die Produktionsmitarbeiter zu erstellen.

Viele Programmierer werden sich dem widersetzen, aber ich persönlich bin der Meinung, dass es nichts auszusetzen hat, wenn man in C / C ++ die Benennung von Funktionen und Variablen im Javadoc-Stil anwendet. Ja, natürlich müssen die Praktiken der Organisation Ihrer Flusskontrolle, der Fadensicherheit usw. unabhängig davon behandelt werden. Ich bin hier jedoch kein Bewerber. Ich weiß auch nicht, wie streng Ihre Anforderungen an das Format des Produktionscodes sind. Ich schlage vor, dass Sie Ihre Anforderungen überprüfen, herausfinden, inwieweit Sie von einer bestimmten Namenskonvention abhängig sind, und eine Lösung wählen, die in den Antworten von mir und anderen erwähnt wurde, ohne sie in einen nicht thematischen Bereich umzuleiten

Hoffe das hat geholfen !?

Hagubär
quelle
Eigentlich habe ich das nach persönlichen C-Codes gefragt. Aber ich werde mich an Ihren Vorschlag erinnern.
Aseem Bansal
@AseemBansal Persönlich oder beruflich, das ist gut zu lernen und auch gut, um Ihren Lebenslauf anzulegen :) .... Bis zu Ihnen.
Hagubear
0

Einige wichtige Dinge, die bei der Benennung beachtet werden müssen, sind:

  1. Schauen Sie sich den Typ actionObject oder ObjectAction an. (Objekt Nicht für C. Aber im Allgemeinen, wenn Sie zu anderen objektorientierten Sprachen wechseln.) Dies sollte helfen

  2. Rest wäre konsequent, kurz und beschreibend sicher.

  3. Haben Sie außerdem einen einzigen Zweck für jede definierte Variable und Funktion, z. B .: Wenn ein Wert temporär gespeichert werden soll, benennen Sie ihn als nTempVal für int
  4. Variablen sollten Nomen und Methoden Verb sein.
JNL
quelle
6
Die ungarische Notation (das Präfixieren einer Variablen mit Buchstaben, die den Typ bezeichnen) führt zu unendlichen Schmerzen. Zum Glück ist es größtenteils aus der Mode gekommen.
Gort the Robot
@StevenBurnap War nur neugierig, warum ungarisches Format vermieden wird? Ich glaube, das haben sie uns in der Schule beigebracht, und ich habe solchen Code auch an einigen Arbeitsplätzen gesehen. Welches würden Sie empfehlen, wenn nicht ungarisch. Danke
JNL
1
Die beste Namenskonvention ist nur eine, die konsequent verwendet wird. Klare, beschreibende Namen werden im Idealfall relativ kurz gehalten, ohne übermäßige Abkürzung, und redundante Präfixe werden vermieden. Die ungarische Notation ist wenig nützlich, erschwert das Lesen von Code und erschwert das Ändern von Typen.
Gort the Robot
2
Hier ist eine Beschreibung der ursprünglichen Absicht und der Abscheulichkeit, zu der die ungarische Notation geworden ist: joelonsoftware.com/articles/Wrong.html
Residuum
@Residuum Das war ein guter Link. Hat mir sehr geholfen. Bin dankbar.
JNL
0

Die meisten Antworten sind gut, aber ich möchte einige Dinge über Namenskonventionen für Bibliotheken und eingeschlossene Dateien sagen, ähnlich wie bei der Verwendung von Namespaces in anderen Sprachen wie C ++ oder Java:

Wenn Sie eine Bibliothek erstellen, suchen Sie ein gemeinsames Präfix für Ihre exportierten Symbole, dh globale Funktionen, Typendefs und Variablen. Dies verhindert Konflikte mit anderen Bibliotheken und identifiziert die Funktionen als von Ihnen stammend. Dies ist ein bisschen Apps ungarischen Notationen.

Vielleicht gehen Sie noch weiter und gruppieren Ihre exportierten Symbole: libcurl verwendet curl_ * für globale Symbole, curl_easy_ *, curl_multi_ * und curl_share_ * für die verschiedenen Schnittstellen. Zusätzlich zur Verwendung von curl_ * für alle Funktionen haben sie eine weitere Ebene von "Namespaces" für die verschiedenen Schnittstellen hinzugefügt: Der Aufruf einer curl_easy_ * -Funktion für ein curl_multi_ * -Handle sieht jetzt falsch aus (siehe Funktionsnamen unter http: // curl). haxx.se/libcurl/c/

Unter Beibehaltung der Regeln für exportierte Symbole sollten Sie diese für statische Funktionen in #includeed-Dateien verwenden: Versuchen Sie, ein gemeinsames Präfix für diese Funktionen zu finden. Vielleicht haben Sie statische String-Utility-Funktionen in einer Datei namens "my_string"? Stellen Sie all diesen Funktionen my_string_ * voran.

Residuum
quelle
Mit exportierten Symbolen sind globale Variablen, Funktionen, Typendefinitionen usw. gemeint, wenn ich richtig bin. Können Sie etwas über die Gruppierung der exportierten Symbole erklären? Ich dachte, Sie haben das bereits im vorigen Absatz erklärt. Was haben Sie im 3. Absatz hinzugefügt?
Aseem Bansal