Style Guide für C

Eines vorneweg: Es gibt nicht den einen, richtigen Weg, Code zu formatieren. Aber es gibt definitiv eine Menge falscher (oder zumindest schlechter) Wege. Daher sollten Sie die unten stehenden Konventionen im Rahmen dieses Kurses einhalten. Auch Unternehmen geben in der Regel eigene, unternehmensweite Konventionen für den Stil vor.

Zeilenlänge

Konventionell beträgt die maximale Länge einer Codezeile in C 80 Zeichen, was historisch auf die Standardgröße von Monitoren auf älteren Computerterminals zurückzuführen ist, die 24 Zeilen vertikal und 80 Zeichen horizontal darstellen konnten. Obwohl moderne Technologie die Begrenzung der Zeilen auf 80 Zeichen überflüssig gemacht hat, ist dies immer noch eine Richtlinie, an der man sich grob orientieren sollte. Eine Zeile in C sollte definitiv nicht länger als 100 Zeichen sein, sonst müssen manche Personen scrollen. Wenn mehr als 100 Zeichen benötigt werden, ist es an der Zeit, entweder die Variablennamen oder das Gesamtdesign zu überdenken.

// These next lines of code first prompt the user to give two integer values and then multiplies those two integer values together so they can be used later in the program
int first_collected_integer_value_from_user = get_int("Integer please: ");
int second_collected_integer_value_from_user = get_int("Another integer please: ");
int product_of_the_two_integer_values_from_user = first_collected_integer_value_from_user * second_collected_integer_value_from_user;

In anderen Sprachen, insbesondere in JavaScript, ist es wesentlich schwieriger, Zeilen auf eine maximale Länge zu beschränken; dort sollte man stattdessen Zeilen an den richtigen Stellen trennen (z. B. durch \n), um die Lesbarkeit und Klarheit zu maximieren.

Kommentare

Kommentare machen den Code lesbarer, nicht nur für andere, sondern auch für Sie selbst, besonders wenn Stunden, Tage, Wochen, Monate oder Jahre zwischen dem Schreiben und Lesen Ihres eigenen Codes vergehen. Zu wenig zu kommentieren ist schlecht. Zu viel zu kommentieren ist aber ebenso schlecht. Wo ist also das richtige Mittelmaß? Alle paar Zeilen Code zu kommentieren (d.h. interessante Blöcke) ist ein guter Richtwert. Versuchen Sie, Kommentare zu schreiben, die eine oder beide dieser Fragen ansprechen:

  1. Wozu dient dieser Block?
  2. Warum habe ich diesen Block auf diese Weise implementiert?

Verwenden Sie innerhalb von Funktionen “Inline-Kommentare” und halten Sie diese kurz (z.B. eine Zeile), da es sonst schwierig wird, Kommentare von Code zu unterscheiden – selbst mit Syntax-Highlighting. Setzen Sie den Kommentar über die Zeile(n), auf die er sich bezieht. Es ist nicht nötig, ganze Sätze zu schreiben, aber das erste Wort des Kommentars sollte groß geschrieben werden (es sei denn, es handelt sich um den Namen einer Funktion, Variable o.ä.). Zwischen dem // und dem ersten Zeichen des Kommentars sollte außerdem ein Leerzeichen stehen. Hier ein richtiges Beispiel:

// Convert Fahrenheit to Celsius
float c = 5.0 / 9.0 * (f - 32.0);

So sollte es nicht aussehen:

//Convert Fahrenheit to Celsius
float c = 5.0 / 9.0 * (f - 32.0);

So auch nicht:

// convert Fahrenheit to Celsius
float c = 5.0 / 9.0 * (f - 32.0);

Und auch nicht so:

float c = 5.0 / 9.0 * (f - 32.0); // Convert Fahrenheit to Celsius

Am Anfang Ihrer .c- und .h-Dateien sollte ein Kommentar stehen, der zusammenfasst, was Ihr Programm (oder die betreffende Datei) tut, z. B:

// Says hello to the world

Zudem sollte auch am Anfang jeder Ihrer Funktionen (außer vielleicht main) ein Kommentar stehen, der zusammenfasst, was Ihre Funktion tut, wie z.B:

// Returns the square of n
int square(int n)
{
    return n * n;
}

Library Headers

Alle Library Header, die Sie einfügen, sollten in alphabetischer Reihenfolge aufgelistet werden, wie hier:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

So können Sie auch bei einer langen Liste auf einen Blick erkennen, ob Sie einen Header eingefügt haben.

Bedingungen

Bedingungen sollten wie folgt formuliert werden:

if (x > 0)
{
    printf("x is positive\n");
}
else if (x < 0)
{
    printf("x is negative\n");
}
else
{
    printf("x is zero\n");
}

Achten Sie darauf, dass:

  • die geschweiften Klammern schön in einer Reihe stehen, jede in einer eigenen Zeile, so dass klar wird, was sich innerhalb der Verzweigung befindet;
  • nach jedem if ein einzelnes Leerzeichen steht;
  • jeder Aufruf von printf mit 4 Leerzeichen eingerückt ist;
  • es einzelne Leerzeichen um das > und um das < gibt; und
  • es kein Leerzeichen unmittelbar nach jedem ( oder unmittelbar vor jedem ) gibt.

Um Platz zu sparen, lassen manche Menschen die erste geschweifte Klammer auf derselben Zeile wie die Bedingung selbst. Wir empfehlen dieses Vorgehen jedoch nicht, da es schwerer zu lesen ist. Also tun Sie – vor allem am Anfang – das folgende nicht:

if (x < 0) {
    printf("x is negative\n");
} else if (x < 0) {
    printf("x is negative\n");
}

Und tun Sie auf keinen Fall das:

if (x < 0)
    {
    printf("x is negative\n");
    }
else
    {
    printf("x is negative\n");
    }

Switches

Deklarieren Sie einen switch wie folgt:

switch (n)
{
    case -1:
        printf("n is -1\n");
        break;

    case 1:
        printf("n is 1\n");
        break;

    default:
        printf("n is neither -1 nor 1\n");
        break;
}

Beachten Sie Folgendes:

  • jede geschweifte Klammer steht in einer eigenen Zeile;
  • nach switch steht ein einzelnes Leerzeichen;
  • es gibt kein Leerzeichen unmittelbar nach jedem ( oder unmittelbar vor jedem );
  • die Fälle des Switches sind mit 4 Leerzeichen eingerückt;
  • die Körper der Fälle sind mit weiteren 4 Leerzeichen eingerückt; und
  • jeder case (einschließlich default) endet mit einem break.

Funktionen

In Übereinstimmung mit C99, stellen Sie sicher, dass Sie main wie folgt deklarieren:

int main(void)
{

}

oder, wenn Sie die CS50-Bibliothek verwenden, mit:

#include <cs50.h>

int main(int argc, string argv[])
{

}

oder mit:

int main(int argc, char *argv[])
{

}

oder auch mit:

int main(int argc, char **argv)
{

}

Deklarieren Sie main nicht mit:

int main()
{

}

und nicht mit:

void main()
{

}

und auch nicht mit:

main()
{

}

Eigene Funktionen sollten ähnlich definiert werden: jede geschweifte Klammer in einer eigenen Zeile und der Rückgabetyp in der gleichen Zeile wie der Funktionsname – so wie wir es bei main gemacht haben.

Einrückung

Um deutlich zu machen, welche Codeblöcke innerhalb anderer Blöcke stehen, rücken Sie Ihren Code jeweils um vier Leerzeichen ein. Wenn Sie dazu die Tabulatortaste Ihrer Tastatur verwenden, stellen Sie sicher, dass Ihr Texteditor so konfiguriert ist, dass er Tabulatoren (\t) in vier Leerzeichen umwandelt. Andernfalls kann es sein, dass Ihr Code auf dem Computer eines anderen Benutzers nicht richtig ausgegeben oder angezeigt wird, da \t in verschiedenen Editoren unterschiedlich dargestellt wird. Wenn Sie CS50 IDE verwenden, ist es in Ordnung, die Tabulatortaste für die Einrückung zu verwenden, anstatt wiederholt auf die Leertaste Ihrer Tastatur zu drücken, da wir ihn so vorkonfiguriert haben, dass er \t in vier Leerzeichen umwandelt.

Hier ist ein schön eingerückter Code:

// Print command-line arguments one per line
printf("\n");
for (int i = 0; i < argc; i++)
{
    for (int j = 0, n = strlen(argv[i]); j < n; j++)
    {
        printf("%c\n", argv[i][j]);
    }
    printf("\n");
}

Schleifen

for

Wann immer Sie temporäre Variablen für die Iteration benötigen, verwenden Sie i, dann j und dann k, es sei denn, spezifischere Namen würden Ihren Code lesbarer machen:

for (int i = 0; i < LIMIT; i++)
{
    for (int j = 0; j < LIMIT; j++)
    {
        for (int k = 0; k < LIMIT; k++)
        {
            // Do something
        }
    }
}

Wenn Sie mehr als drei Variablen für die Iteration benötigen, ist es vielleicht an der Zeit, Ihren Ansatz zu überdenken.

while

Deklarieren Sie while-Schleifen wie folgt:

while (condition)
{
    // Do something
}

Beachten Sie Folgendes:

  • jede geschweifte Klammer steht in einer eigenen Zeile;
  • nach while steht ein einzelnes Leerzeichen;
  • es gibt kein Leerzeichen unmittelbar nach dem ( oder unmittelbar vor dem ); und
  • der Schleifenkörper (in diesem Fall ein Kommentar) ist mit 4 Leerzeichen eingerückt.

do … while

Deklarieren Sie do ... while-Schleifen wie folgt:

do
{
    // Do something
}
while (condition);

Beachten Sie Folgendes:

  • jede geschweifte Klammer steht in einer eigenen Zeile;
  • nach while steht ein einzelnes Leerzeichen;
  • es gibt kein Leerzeichen unmittelbar nach dem ( oder unmittelbar vor dem ); und
  • der Schleifenkörper (in diesem Fall ein Kommentar) ist mit 4 Leerzeichen eingerückt.

Pointer

Wenn Sie einen Pointer deklarieren, schreiben Sie das * neben die Variable, wie hier:

int *p;

Schreiben Sie es nicht neben den Typ, wie hier:

int* p;

Variablen

Da CS50 und Inf-Einf-B sich nach dem Standard C99 richten, sollten Sie nicht alle Ihre Variablen ganz oben in Ihren Funktionen definieren, sondern nur dort, wo Sie sie tatsächlich benötigen. Außerdem sollten Sie den Scope Ihrer Variable – also den Bereich, in dem die Variable gültig ist – so klein wie möglich halten. Wenn zum Beispiel i nur für eine Schleife benötigt wird, deklarieren Sie i innerhalb der Schleife selbst:

for (int i = 0; i < LIMIT; i++)
{
    printf("%i\n", i);
}

Obwohl es in Ordnung ist, Variablen wie i, j und k für die Iteration zu verwenden, sollten die meisten Ihrer Variablen spezifischer benannt werden. Wenn Sie zum Beispiel einige Werte summieren, nennen Sie Ihre Variable sum. Wenn der Variablenname aus zwei Wörtern besteht (z.B. is_ready), setzen Sie einen Unterstrich dazwischen. Dies ist eine Konvention, die in C beliebt ist, in anderen Sprachen jedoch weniger.

Wenn Sie mehrere Variablen desselben Typs auf einmal deklarieren, ist es in Ordnung, sie zusammen zu deklarieren, wie hier:

int quarters, dimes, nickels, pennies;

Initialisieren Sie nicht nur manche, wie hier:

int quarters, dimes = 0, nickels = 0 , pennies;

Achten Sie auch darauf, Pointer getrennt von Nicht-Pointern zu deklarieren, wie hier:

int *p;
int n;

Deklarieren Sie Pointer nicht in der gleichen Zeile wie Nicht-Pointer, wie hier:

int *p, n;

Strukturen

Deklarieren Sie eine struct als Typ wie folgt: Jede geschweifte Klammer steht auf einer eigenen Zeile, die Elemente darin sind eingerückt, und der Name des Typs steht ebenfalls auf einer eigenen Zeile. Wie hier:

typedef struct
{
    string name;
    string dorm;
} student;

Enthält die struct einen Pointer auf eine andere solche struct, so deklarieren Sie die struct mit einem Namen, der mit dem Typ identisch ist, ohne Unterstriche zu verwenden:

typedef struct node
{
    int n;
    struct node *next;
} node;