Layout

  • Allgemeines
  • Ausdrücke
  • Steuerkonstrukte
  • Verbundtyp
  • Klasse
  • Eingangsprüfende Schleife
  • Ausgangsprüfende Schleife
  • Zählschleife
  • Binäre Auswahl
  • Auswahl
  • Funktionen
  • Funktionsdeklaration
  • Funktionsdefinition
  • Funktionsaufruf
  • Datentypen und Datenobjekte
  • Module
  • Kommentare

  • Allgemeines

    1. Jede Zeile Quellcode enthält höchstens eine Anweisung.
    2. Zeilen sollen die Länge von 80 Zeichen nicht überschreiten. Zu lange Ausdrücke werden in mehrere Zeilen umgebrochen. Die Folgezeilen werden um eine Ebene eingerückt.
      1. nZaehler =
            10 * Intervallbeginn() * OFFSET - Sicherheitsabstand();

    3. Die Tabulatorbreite beträgt 4 Zeichen. Die Größe ist im Dateikopf anzugeben.
    4. Die Einrückungstiefe beträgt 1 Tabulatorschritt (bzw. 4 Zeichen, falls die Tabulatorweite abweicht).
    5. Vor einem Semikolon oder Komma wird kein Whitespace (Leerzeichen, Tabulator, Zeilenwechsel) gesetzt.
    6. Nach einem Semikolon oder Komma steht immer ein Leerzeichen oder ein Zeilenwechsel.
    7. Einzelne Dateien sollten nur in Ausnahmefällen länger als 1.500 Zeilen sein.
    8. Für Datei- und Funktionsköpfe werden Kommentarvorlagen verwendet.

    Ausdrücke

    1. Muß ein geklammerter Ausdruck umgebrochen werden (z.B. eine lange if-Bedingung oder die Parameterliste einer Funktion), so stehen die äußeren Klammern untereinander auf der jeweils selben Einrückungsebene und werden um eine Ebene eingerückt, um Verwechslungen mit geschweiften Klammern zu vermeiden). Der Ausdruck in der Klammer wird um eine weitere Ebene eingerückt.
      1. if
            (
                ((MIN_INTERVAL < nZaehler) && (MAX_INTERVAL > nZaehler)) ||
                (0 == nZaehler)
            )
        {
            Anweisungen();
        }

        memcpy
            (
                pZiel,
                pQuelle,
                lGroesse
            );

    2. Vor und nach Operatoren wird ein Leerzeichen gesetzt.
    3. Die Operatoren Dereferenzierung und Adresse stehen jedoch ohne Leerzeichen bei dem Namen, für den sie angewendet werden. Werden sie für einen Ausdruck verwendet, ist dieser Ausdruck zu klammern.

      C/C++

      Pascal/Delphi

      int i = 27 * *pSumme;
      y = f(17 + &x);
      float x = *(pPuffer->m_pDaten);
      i := 27 * pSumme^;
      y := f(17 + @x);
      x := (pPuffer^.m_pDaten)^;
    4. Zeiger und Referenzen werden deklariert, indem der entsprechende Operator an den Typ geschrieben wird. Zu bevorzugen ist es jedoch, mittels typedef einen passenden Typ zu deklarieren.
        1. double* pSumme;
          float Funktion(const CComplex& Naeherung);

        besser:

      C/C++

      Pascal/Delphi

      typedef double* PDOUBLE;
      PDOUBLE pMittelwert, pVarianz;
      type PDOUBLE = ^double;
      var pMittelwert, pVarianz: PDOUBLE;
    5. Klammern werden innen und außen ohne Leerzeichen gesetzt. Ausnahme: Klammern vor oder nach Operatoren bzw. nach Schlüsselworten.
        1. f(c), Pi() + 13, if (bBedingung),

        aber nicht:

          f (c), f( c ), Pi()+13

    6. Bei Vergleichen sollte die Konstante immer links stehen, damit nicht versehentlich eine Zuweisung entsteht.
      1. if (NULL == pDatenpuffer)
        {
            return;
        }

    7. Type-Casts haben immer die Form
      1. LONG(nAnzahl) * Groesse(); // C++

      bzw.

        (LONG)(nAnzahl) * Groesse(); /* C */

      und nicht

        (LONG) nAnzahl * Groesse();

      damit der Bereich des Casts deutlich wird.

    8. (C, C++) Der ?-Operator ist sparsam zu verwenden. Im Zweifelsfall ist eine if-else-Konstruktion vorzuziehen. Der ?-Operator darf nicht auf mehrere Zeilen umgebrochen werden (in diesem Fall ist auf jeden Fall if-else zu verwenden). Wenn eine Komponente in einem ?:-Ausdruck selbst ein zusammengesetzter Ausdruck ist, so ist diese zu klammern:
      1. nLaenge = (NULL != p) ? ::strlen(p) : 0;
            // Parameter von ::strlen() darf nicht NULL sein.

    Steuerkonstrukte

    1. Öffnende und schließende geschweifte Klammer stehen auf der selben Einrückungsebene wie die sie umgebenden Anweisungen.
      1. C/C++

        Pascal/Delphi

        Anweisungen();

        for (i = 0; LIMIT > i; ++i)
        {
            Anweisungen();
        }

        Anweisungen();

        Anweisungen;

        for i := 0 to Pred(LIMIT) do
        begin
            Anweisungen;
        end {for};

        Anweisungen;

    2. Vor (Schlüsselwort) und nach (schließende geschweifte Klammer) einem Steuerkonstrukt wird eine Leerzeile eingefügt (die Leerzeile vor einem else ist optional), es sei denn in der vorhergehenden Zeile steht nur eine öffnende geschweifte Klammer. Steuerkonstrukte werden wie folgt angeordnet:
    3. Steuerkonstrukt

      C/C++

      Pascal/Delphi

      Verbundtyp

      typedef struct
      {
          float m_fReal;
          float m_fImag;
      } CComplex;
      type CComplex =
      record
          m_fReal: single;
          m_fImag: single;
      end {record};

      Klasse

      class C : CBasis
      {
          public:
              C(void);

          private:
              int m_nGroesse;
      };

      type C =
      class (CBasis)
          public
              constructor Create;

          private
              m_nGroesse: integer;
      end {class};

      eingangsprüfende
      Schleife

      while (bAusdruck)
      {
          Anweisungen();
      }
      while (bAusdruck) do
      begin
          Anweisungen;
      end {while};

      ausgangsprüfende
      Schleife

      do
      {
          Anweisungen();
      } while (bAusdruck);
      repeat
          Anweisungen;
      until (not bAusdruck);

      Zählschleife

      for (i = 0; i < MAXIMUM; ++i)
      {
          Anweisungen();
      }
      for i := 0 to Pred(MAXIMUM) do
      begin
          Anweisungen;
      end {for};

      Binäre
      Auswahl 

      if (bAusdruck)
      {
          Anweisungen();
      }

      else if (bAusdruck)
      {
          Anweisungen();
      }

      else
      {
          Anweisungen();
      }

      if (bAusdruck) then
      begin
          Anweisungen;
      end

      else if (bAusdruck) then
      begin
          Anweisungen;
      end

      else
      begin
          Anweisungen;
      end {if};

      Auswahl

      switch (nAuswahl)
      {
          case 1:
          {
              Anweisungen();
              break;
          }

          default:
          {
              Anweisungen();
              break;
          }
      }

      case (nAuswahl) of
          1:
          begin
              Anweisungen;
          end;

          else
          begin
              Anweisungen;
          end;
      end {case};

      (C, C++) Case-Labels in einer switch-Anweisung dürfen zusammengefaßt werden (d.h. zwischen den Case-Labels steht kein Code). Darauf ist am Beginn der Gruppe hinzuweisen. Fehlt die break-Anweisung zwischen zwei Fällen (d.h. zwischen den Case-Labels steht Code), so ist hierauf deutlich hinzuweisen und das Folge-Label ist in dem Kommentar ausdrücklich zu erwähnen!

        switch (nNumber)
        {
            case 1:
                int n = 0;
                Anweisungen();
                break;

            // Fall-Gruppe: Erläuterung der Gemeinsamkeit
            case 2:
            case 3:
            case 4:
                Anweisungen();
                break;

            case 5:
                Anweisungen();
                //-- Kein break; weiter bei 6 --//

            case 6:
                Anweisungen();
                break;
        }

      (C) Alternativ kann eine switch-Anweisung auch derart formatiert werden, daß die Anweisungen eine und die Case-Labels eine halbe Ebene weit eingerückt werden, wenn aufgrund compilerspezifischer Gegebenheiten (Effizienzgründe) der Aufruf von Funktionen zu teuer wäre und mehrere Steuerkonstrukte im switch-Block verschachtelt werden müssen:

        switch (nNumber)
        {
          case 1:
            Anweisungen();
            break;

          default:
            Anweisungen();
            break;
        }

    4. Der Block eines Steuerkonstrukts ist immer mit geschweiften Klammern zu umschließen (C, C++ Ausnahme: case-Label in einer Fallgruppe), auch wenn er leer ist:
      1. while (!IstTimerAbgelaufen())
        {
        }

    5. Die Bedingung eines Steuerkonstrukts steht niemals auf derselben Zeile wie die Anweisung.
    6. while (bBedingung)
      {
          Anweisung();
      }

      while (Bedingung())
      {
      }

      Unzulässig: while (bBedingung) Anweisung();
      while (bBedingung);

    Funktionen

    Funktionsdeklaration

    1. Bei Funktionsdeklarationen werden entweder alle Parameter einer Funktion in einer Zeile oder jeder Parameter in einer getrennten Zeile aufgeschrieben. (C) Funktionsdeklarationen in K&R-Syntax sind unzulässig.

      C/C++

      int Summe(const int n1, const int n2, float f);

      void PushBefehl
          (
              PStack pBefehlsStack,
              const CBefehl einBefehl
          );

      Pascal/Delphi

      function Summe(const n1, n2: integer; f: single): integer;

      procedure PushBefehl
          (
              pBefehlsStack: PStack;
              const einBefehl: CBefehl
          );

    1. Jede Funtion wird in einer eigenen Zeile deklariert und kommentiert. Mehrere Funktionen dürfen in einem einzigen Kommentar beschrieben werden, wenn sie sich lediglich in der Parameterliste unterscheiden und die-selben Aufgabe(n) haben.
    2. (C, C++) Hat die Funktion keine Parameter, wird das Schlüsselwort void verwendet.
      1. void VerschwendeZeit(void);

    Funktionsdefinition

    1. Bei der Funktionsimplementierung wird jeder Parameter in einer eigenen Zeile aufgeführt. Die Parameter sind zu kommentieren. (C++) Default-Parameter sind (auskommentiert) mit aufzuführen.
    2. C/C++

      Pascal/Delphi

      void PushBefehl
      // Kommentare
          (
              PStack pBefehlsStack,
                  // Liste der ausgeführten Befehle
              const CBefehl einBefehl
                  // abzulegender Befehl
          )
      {
          Anweisungen();
      }

      int Systemstatus
      // Kommentare
          (
              const BOOL bNurFehler /* = TRUE */
                  // Es werden nur Fehler gemeldet
          )
      {
          Anweisungen();
      }

      procedure PushBefehl
      // Kommentare
          (
              PStack pBefehlsStack,
                  // Liste der ausgeführten Befehle
              const CBefehl einBefehl
                  // abzulegender Befehl
          )
      {
          Anweisungen;
      }
    1. (C++) Die Initialisierer der Datenelemente sind in einem Konstruktor jeweils in eine eigene Zeile zu schreiben.
      1. CComplex::CComplex
        //
        Kommentare
            (void)
        : m_dfRealteil(0.0),
          m_dfImaginaerteil(0.0)
        {
        }

    Funktionsaufruf

    1. (C++) Beim Aufruf einer Funktion, die kein Klassenelement ist, wird dem Namen der zugehörige Namespace vorangestellt.

    C++

    Pascal/Delphi

    if (0 < ::strlen(lpszName))
    {
        ::printf("Hallo %s.", lpszName);
    }
    if (0 < System.Length(sName))
    begin
        System.Write('Hallo ', sName, '.');
    end {if};

    Datentypen und Datenobjekte

    1. Jede öffentliche Variable wird in einer eigenen Anweisung deklariert und kommentiert.
      1. int msg_nGesamtFehleranzahl = 0; // Anzahl aller im System aufgetretenen Fehler
        int msg_nLetzteFehleranzahl = 0; // Anzahl der beim letzten Funktionsaufruf
                                         // aufgetretenen Fehler

        Unzulässig:

          int msg_nGesamtFehleranzahl = 0, msg_nLetzteFehleranzahl = 0;
              // Anzahl der insgesamt bzw. beim letzten Funktionsaufruf
              // aufgetretenen Fehler

    2. Jedes Datenobjekt wird in einer eigenen Anweisung deklariert und kommentiert.
      1. Unzulässig:

          private:
              CKlasse m_a, m_b, m_c;

    3. (C++) Die Deklarationsabschnitte innerhalb von Klassen erfolgen in der Reihenfolge publicprotectedprivate, innerhalb der einzelnen Abschnitte zunächst weitere Definitionen und Deklarationen (Typen und Klassen), dann die Funktionselemente und zuletzt die Datenelemente.
    4. (C++/Delphi) Properties dürfen am Ende aufgeführt werden, da Properties auch auf private-Elemente zugreifen können.

          class CLinientyp
          {
              public:
                  //-- Konstruktoren --//
                  CLinientyp
                  (
                          const int nLinientyp = SOLID_LINE,
                          const int nLiniendicke = NORM_WIDTH,
                          const unsigned uLinienmuster = 0
                  );
                  //-- Selektoren --//
                  int Linientyp(void) const;
                  int Liniendicke(void) const;
                  unsigned Linienmuster(void) const;
                  //-- Modifier --//
                  void VerwendeLinientyp(const int nLinientyp);
                  void VerwendeLiniendicke(const int nLiniendicke);
                  void VerwendeLinienmuster(const unsigned uLinienmuster);
              protected:
                  //-- Agenten --//
                  virtual void Drucke(void);
                  virtual void Zeichne(void);
              private:
                  //-- Datenelemente --//
                  int m_nLinientyp;
                  unsigned m_uLinienmuster;
                  int m_nLiniendicke;
          };
    5. (C++) Die Funktionsdeklarationen werden thematisch gruppiert. Die Gruppen sind durch Kommentare abzugrenzen. Innerhalb dieser Gruppen werden zunächst polymorphe, dann nicht-polymorphe Funktionen angegeben. Die Reihenfolge der Gruppen ist in jedem der Zugriffsbereiche (public, protected, private) gleich.
    6. (Pascal/Delphi) Auch wenn die Namen von einfachen Datentypen (integer, double, etc.) in Pascal keine Schlüsselwörter sind, werden sie klein geschrieben. Dadurch ist die Schreibweise konsistent zu C/C++. Außerdem wird folgende verwirrende Konstruktion vermieden:
      1. Unzulässing und verwirrend:

        var u: Cardinal;
        var n: Integer;
        var x: Double;

        n := Integer(u);  // Achtung Type-Cast…
        u := Trunc(x);    // …aber hier Funktionsaufruf!

        (etwas) besser:

        n := integer(u);  // Type-Cast
        u := Trunc(x);    // Funktionsaufruf

    Module

    1. (C/C++) Die Deklarationsdatei enthält Konstantendefinitionen, Typdefinitionen und Funktionsprototypen, die auch für andere Module bestimmt sind. Diese Datei wird von folgendem Rahmen umgeben, um ein mehrfaches #include zu vermeiden:
      1. #ifndef _FILENAME_H
        #define _FILENAME_H
            ...
        #endif

    2. In der Implementierungsdatei wird die Deklarationsdatei (u.U. mit weiteren Deklarationsdateien) per #include eingeladen. Die in der Deklarationsdatei genannten Funktionen werden hier implementiert. Private Variablen und Funktionen werden mit static definiert.
    3. Module müssen keine Funktionen definieren. Wenn nur Typen oder Konstanten definiert sind, entfällt die Implementierungsdatei.
    4. (C, C++) Es ist nicht erlaubt, Implementierungsdateien (.C bzw. .CPP) per #include einzuschließen.
    5. (C++) Bei der Implementierung von Template-Klassen kann die Implementierung der Funktionen in eine eigene Datei ausgelagert werden. Diese erhält die Erweiterung .h und wird nicht von der die Schnittstelle der Klasse beschreibenden Header-Datei mit #include eingeschlossen.

    6. Die Korrektheit von Modulen wird durch den Compiler geprüft. Bei maximal möglicher Warnungsstufe dürfen keine Warnungen ausgegeben werden.
    7. (C) Wenn möglich und nicht bereits durch Compiler-Funktionalität erfüllt, ist eine Prüfung per lint durchzuführen.

    Kommentare


    [zurück] | [weiter] | [Inhalt] | [Einleitung] | [Programmierstil] | [Anhänge]


    Copyright © 1996-97 by Uwe Sauerland