Einleitung

Diese Konventionen sind als Anhaltspunkte und Richtlinien zur Stilbildung zu verstehen. Im Zweifelsfall sollten sie herangezogen werden, um eine Entscheidung zwischen mehreren möglichen Alternativen zu ermöglichen. Dies ist als Service gedacht, um die Vergabe (oder den Abzug) von Punkten aufgrund von Stilfragen fair und nachvollziehbar zu halten. Es muss nicht pedantisch jedes einzelne Statement auf Übereinstimmung mit allen Punkten überprüft werden, aber grobe Abweichungen (d.h. massive oder wiederholt auftretende, oder komplette Missachtungen einzelner Punkte) sollten vermieden werden.

Einrückung und Leerzeichen

Klammern sollen im "Exdented Style" gehalten sein, d.h. sie werden nicht mit eingerückt. Ausdrücke innerhalb der Klammern werden relativ zu diesen eingerückt.

Einrückung besteht aus 4 Leerzeichen vom Beginn der umschließenden Deklaration oder des Ausdrucks an, und sollte mit Tabs erfolgen (Tab-Weite im Editor entsprechend einstellen).

Beispiel:
void f(int a)
{
    int i;
    if (a > 0)
    {
        i = a;
        foo = bar;
    }
    else
        i = -a;
}
class A
{
};
Weitere mögliche Varianten:
void f(int a) {
    int i;
    if (a > 0) {
        i = a;
        foo = bar;
    }
    else
        i = -a;
}
void f(int a)
    {
    int i;
    if (a > 0)
        {
        i = a;
        foo = bar;
        }
    else
        i = -a;
    }

Jeder Ausdruck soll (für gewöhnlich) auf einer eigenen Zeile stehen.

Code muss nicht um jeden Preis kompakt gemacht werden. Mehrere Statements auf einer Zeile erschweren es, den Code zu lesen.

Alle binären arithmetischen, Bitoperatoren und Zuweisungsoperatoren sowie der Konditional-Operator (?:) sollen links und rechts von genau einem Leerzeichen umgeben sein; dem Komma-Operator soll ein Leerzeichen folgen, aber nicht vorangehen; alle anderen Operatoren sollen ohne Leerraum benutzt werden.

Zeilen sollen die Länge von 80 Zeichen nicht überschreiten.

Dies ist Konvention. Ebenfalls nützlich beim Ausdrucken.

Blöcke

Anweisungsblöcke sollen nur eingeführt werden, wenn sie wirklich nötig sind.

Die einzelnen Anweisungen stehen dann direkt unter der if-Abfrage (for-Schleife, while-Schleife, etc.)

Beispiel:
void f(int a)
{
    int i;
    
    if (a > 0)
        i = a;
    else
        i = -a;
}

anstatt

Beispiel (falsch):
void f(int a)
{
    int i;
    if (a > 0)
    {
        i = a;
    }
    else
    {
        i = a;
    }
}
Man kann hier einwenden, daß dies beim späteren Editieren Probleme verursachen könnte, wenn man nicht darauf achtet, notwendig gewordene Klammern hinzuzufügen. Ich gehe davon aus, daß man dies in dem Fall sofort an der automatischen Einrückung durch den Editor ersehen kann.

Namensgebung

Namen sind komplett in Kleinbuchstaben gehalten, und Wörter sind durch einen Unterstrich (_) voneinander getrennt.

Beispiel: int max_points, int current_sum;

Konstanten bestehen dagegen ausschließlich aus Großbuchstaben und dem Unterstrich.

Beispiel: const int MAX_INPUT_SIZE = 50;

Klassennamen beginnen mit einem Großbuchstaben, Namen von Objekten dagegen (wie bereits gesagt) mit einem Kleinbuchstaben.

Beispiel: Vector my_vector;

Namen

Eingängige, beschreibende Namen verwenden.

Temporär eingeführte Variablen (z.B. in einer for-Schleife oder als Puffer zum Einlesen von Daten) sollen kurze Namen bekommen. Ein Programmierer, der solche Variablennamen sieht, soll annehmen dürfen, daß ihr Gültigkeitsbereich einige Zeilen Code nicht überschreitet. Verbreitete Namen solcher Variablen sind i, j, k, m, n und für Zeichen (character) c und d.

Ebenfalls möglich sind Varianten wie ii oder jj, was sich besonders dann anbietet, wenn man diese später automatisiert durch andere Namen ersetzen möchte.

Kommentare

Jeglicher Kommentar bezieht sich auf die direkt nachfolgende Zeile(n) und ist identisch zu dieser (diesen) eingerückt

Konsistenz in der Plazierung von Kommentaren hilft, Probleme bei deren Zuordnung zu vermeiden.

Ebenfalls in Ordnung sind kurze Erklärungen zu einem Ausdruck direkt auf der gleichen Zeile, mit etwas Abstand zum Ausdruck selbst.

Zu jeder (selbst definierten!) Klasse gehört ein Kommentar, der ihren Zweck erklärt.

Dateien

In jedem Header-File wird genau eine nach außen sichtbare Klasse definiert.

So wenig Deklarationen wie möglich in einem Header-File zu haben, reduziert Header-Abhängigkeiten.

Die Header-Datei hat den gleichen Namen wie die Klasse und die Endung .h.

Externe "non-member" Funktionen, die dennoch zum Interface einer Klasse gehören, dürfen im gleichen Header-File deklariert werden.

Dateinamen sollen als "case sensitive" behandelt werden (Groß- und Kleinschreibung macht einen Unterschied).

Header-Files müssen einen "include" Schutz aufweisen.

Der "include" Schutz bewahrt das Header-File davor, mehrfach eingebunden zu werden.

Beispiel:

#ifndef FILE_H
#define FILE_H
...
#endif

Der Makroname, der im "include" Schutz eingeführt wird, soll den gleichen Namen wie die Datei haben (ohne Erweiterung), gefolgt von dem Suffix "_H".

Header-Files sollen in sich abgeschlossen sein

Wenn ein Header-File eingebunden wird, soll es nicht notwendig sein, zuvor andere Header-Files einzubinden.

Eine einfache Art, dies zu überprüfen, ist, die Datei als erstes in sich selbst einzubinden.
Beispiel:

/* foobar.h */

#include "foobar.h"
#include <stdio.h>

...

System-Header sollen mit <> eingebunden werden, Projekt-Header mit "".

Beispiel: Siehe oben.

#include Direktiven stehen am Anfang einer Datei.

Alle #include Direktiven an einem Platz zu haben, hilft, sie schnell zu finden. Außerdem stehen sie so sicher vor dem Code, der sie benötigt.

Es sollen keine absoluten Pfade oder Dateinamen in #include Direktiven verwendet werden.

Andere Systeme könnten eine andere Verzeichnisstruktur haben.

Beispiel (falsch): #include "C:\Uni\SS05\Prog2\uebung01\aufgabe01.h"

Deklarationen

Parameternamen sollen in der Deklaration einer Funktion mit angegeben werden.

Parameternamen sind nützlich, um zu dokumentieren, wozu der Parameter dient.

Parameternamen sollen in allen Deklarationen und der Definition der Funktion übereinstimmen!

Deklariere geerbte Methoden virtual.

Eine vererbte Methode ist implizit bereits virtual, wenn sie in der Basisklasse als virtual deklariert war. Wiederhole das virtual Schlüsselwort in der Deklaration der abgeleiteten Klasse, um deutlich zu machen, daß diese Methode virtual ist.

Benutze keine globalen Variablen.

Benutze stattdessen Singleton Objekte.

Benutze keine globalen using Deklarationen in Header-Files.

Dies kann Konflikte mit sich bringen, wenn noch andere Header eingebunden werden.

Die Teile einer Klassendefinition sind public, protected und private, in dieser Reihenfolge.

Dies erleichtert das Lesen der Definition, da sich die meisten Leser am ehesten für das public Interface interessieren werden.

Deklariere Klassendaten private.

Klassen sollen ihre Informationen einkapseln, und nach außen nur Zugriff über dafür vorgesehene Funktionen darauf anbieten. So wird Konsistenz der Daten garantiert.

Die Ausnahme zu dieser Regel ist der Datentyp struct, der nur Variablen beinhaltet.

Statements

Benutze niemals gotos.

Gotos erzeugen Spaghetticode. Niemand will Spaghetticode.

Zu jedem switch Ausdruck gehört ein default Label.

Wenn dieser Fall niemals eintreten kann, sollte dies durch eine Assertion zum Ausdruck gebracht werden.

Andere Themen

Benutze Preinkrement/Predekrement anstatt von Postinkrement/Postdekrement, wenn dies sonst keinen Unterschied macht.

Für Postinkrement/Postdekrement muss der Compiler eine zusätzliche temporäre Variable einführen, um den alten Wert der Variable zu speichern. Obwohl diese für primitive Datentypen wieder wegoptimiert werden kann, ist es gut, sich diese Notation anzugewöhnen.

Verlasse dich nicht auf implizite Konvertierung nach bool in Konditionalen.

Beispiel:
if (ptr)         // falsch
if (ptr != NULL) // ok

Generated 2005-04-16 by
Coding Standard Generator version 1.12.
Übersetzt von Andi Scharfstein, 19.04.2005