Kodierrichtlinien für Quelltexte

Um die Quellcodes einheitlich und lesbar zu gestalten, müssen die in diesem Dokument festgelegten Richtlinien für die Gestaltung verwendet werden.

Dieses Dokument gliedert sich in folgende Abschnitte:

Allgemein

Quelltext-Struktur

Bezeichnungskonventionen

 

Allgemein

Compiler

Es sind die C/C++-Compiler von Microsoft und Borland zulässig. Es dürfen darum keine automatischen Registervariablen verwendet werden und die Daten müssen byteweise ausgerichtet werden.

 

Datentypen

Wenn nicht von vorhandenen Prototypen anders verlangt, müssen immer die Datentypen aus der Headerdatei ‘typedefs.h’ verwendet werden. Folgende Datentypen sind definiert:

Definierte Datentypen
Typname Größe in Bytes Notiz
SInt8_t 1  
UInt8_t 1  
SInt16_t 2  
UInt16_t 2  
SInt32_t 4  
SInt32_t 4  
Char_t 1  
Byte_t 1  
Boolean_t 1 Werte sind TRUE/FALSE. Definition kann zwischen verschiedenen C-Compilern variieren
Data_t - void-Zeiger
Flags_t 2 Für jede Art von Flags zu verwenden
String_t - Zeiger auf eine Zeichenkette. Definiert als const char*
HEnum_t 4 Handle für Iterationen.
TimeCode_t 4 Enthält einen Zeitcode in Sekunden seit dem 1. Jänner 1901

 

Debugging

In den Source-Codes können für Testzwecke Debug-Makros eingebaut werden. Es sind allerdings nur die Makros aus der Datei ‘debug.h’ gültig. Die dazugehörige Library trägt den Namen ‘chlibdb.dll’ (bzw. die Version für GUI-Tracing namens 'chlibdb_gui.dll').

 

Global definierte Makros

Diese Makros müssen gegebenenfalls in den Quelltextdateien definiert werden. Die Definition muß vor der ersten ‘#include’-Anweisung stattfinden.

__MIDL_PASS__

Dieses Makro muß bei einem MIDL-Compiler-Lauf definiert sein.

__BUILD_LIBRARYS__

Muß bei der Erstellung der Bibliotheken (Quellcode für API-DLL's) definiert sein. Hiermit wird das Makro ‘API_EXPORT’ korrekt expandiert.

__RPC_PROCEDURES__

Wenn eine Sourcecodedatei vom MIDL-Compiler erzeugte Headerdateien einbindet, muß dieses Makro definiert sein.

 

Sprache

Alle Teile des Quellcodes (insbesondere Variablen- und Funktionsnamen) sind grundsätzlich in Englisch zu verfassen. Einzige Ausnahme sind Kommentare, die auch in Deutsch verfaßt werden können.

 

Tabulator

Im Quellcode dürfen keine Tabulatorzeichen gespeichert werden. Diese Editoroption muß deaktiviert werden. Der Editor muß die Tabulatorschritte mit Leerzeichen auffüllen. Die Tabulatoreinrückung (mit Leerzeichen gefüllt) beträgt 3 Zeichen.

 

 

Quelltext-Struktur

Abschnitte

Ein Modul enthält verschiedene Abschnitte. Unter einem Abschnitt versteht man z.B. ‘Include-Dateien’, ‘Globale Variablen’, ‘Funktionsprototypen’.

Abschnitte werden folgendermaßen begonnen:

/*s---------------------------------------------------------------------
   Abschnittname
----------------------------------------------------------------------*/

Umfangreichere Abschnitte (z.B. ab jetzt die Implementation einer bestimmten Klasse) werden folgendermaßen deklariert:

/*m---------------------------------------------------------------------
    *********************** Abschnittname ************************
----------------------------------------------------------------------*/

 

Blöcke

Bei Blöcken wird immer zwei Zeichen eingerückt. Dies entspricht folgender Darstellung:

for( i=0; i<x; i++ )
  {
  if( i==y )
    {
    //
    // Kommentar
    //
    ...
    }
  }

 

Externes ‘C’

Wenn die Header-Datei von C benutzt werden kann, müssen die geeigneten Schutzmechanismen (sentries) für die Prototypen eingefügt werden:

#if defined (__cplusplus)
extern "C" {
#endif
//
// Funktionsprototypen
//
#if defined (__cplusplus)
}
#endif

 

Funktionen

Die Implementationen von Funktionen haben folgende Form:

Rückgabewert Funktionsname
   (
   Typ param1,
   Typ param2
   )
{
   ...
   Code
   ...
}

 

Funktionsnamen beginnen grundsätzlich mit Großbuchstaben. Einzelne Worte innerhalb des Funktionsnamens sind durch einen großen Anfangsbuchstaben zu kennzeichnen. z.B. SelectListboxString. Innerhalb von Funktionsnamen kein ‘_’ verwenden.

Der Rückgabewert einer Funktion muß immer vom Typ ‘Retcode_t’ sein. Ausnahmen sind lokale Funktionen (siehe Funktionsprototypen).

 

Funktionskopf

Jede Funktion muß einen Funktionskopf mit einer Funktionsbeschreibung verfügen:

/*f--------------------------------------------------------------------
   Funktionsname
   Description:
    (1)

   Return:
    (2)

   Called functions (Module/Name):
    (3)

   Memory allocation:
    (4)

   Author:
    (5)
---------------------------------------------------------------------*/

(1) Kurze Beschreibung der Vorgänge in der Funktion. Besonderheiten (Algorithmen, ev. Auswirkungen auf globales Programm) müssen hier vermerkt werden.

(2) Alle möglichen Rückgabewerte werden hier aufgelistet. Bei Bedarf ist zu vermerken, wie dieser Rückgabewert zustande gekommen ist.

(3) Eine Liste aller aufgerufenen Funktionen in der Form Modul/Name. Als Modul gilt eine Quellcodedatei oder bei Produkten von Fremdherstellern der Name der Bibliothek. Werden C++-Funktionen aufgerufen, muß auch die Klasse vermerkt werden (z.B. TEdit::GetText)

(4) Hier wird vermerkt, ob die Funktion Speicher allokiert und wenn ja, wo dieser wieder freigegeben wird.

(5) Der Name des Autors.

Ein gültiger Funktionskopf sieht folgendermaßen aus:

/*f--------------------------------------------------------------------
   BuildMessageDataForModules
   Description:
    Erzeugt eine Nachrichtendatenstruktur, die den Weiterleitungs-
    modulen direkt übergeben werden kann.
    ACHTUNG: Es wird Speicher reserviert, der extern freigegeben
    werden muß.

   Return:
    Bei Erfolg RC_SUCCESS, sonst
     - RC_NOT_ENOUGH_MEMORY, wenn nicht genügend Speicherplatz
       vorhanden ist.
     - RC_NO_DATA, wenn die Nachricht nicht in der Datenbank
       verzeichnet ist.
     - Rückgabewert von IMBGetApplication

   Called functions (Module/Name):
    apiserver.cpp/GetMessage
    apiserver.cpp/RPCGetCustomerInformation
    apiserver.cpp/InitializeReceiverData
    imdb.dll/IMDBFreeMemory
    imdb.dll/IMDBGetApplication
    C++/new
    C++/delete[]
    Win32/lstrcpy

   Memory allocation:
    Dynamischer Speicher wird reserviert und über
    mMessage->data zurückgegeben. Diese Speicher muß vom
    Aufrufer wieder freigegeben werden.

   Author:
    Alexander Berger
---------------------------------------------------------------------*/

Der Funktionsprototyp benötigt keinen Kopf.

 

Funktionsprototypen

Prototypen von Funktionen werden immer in folgender Form angegeben:

Rückgabewert Funktionsname(
   Typ param1,
   Typ param2,
   Typ param3,
   Typ param4,
   Typ param5 );

Lokale Funktionen sind als solche zu kennzeichnen. Dies wird vom Makro ‘LOCAL’ übernommen, welches dem Funktionsprototyp vorangestellt wird (z.B. LOCAL Rückgabewert Funktionsname(...); ).

Parameter müssen immer in folgender Anordnung angegeben werden:

 

Globale Variablen

Die Anzahl globaler Variablen sollte möglichst gering gehalten werden. Wenn eine globale Variable benötigt wird, sollte sie als globaler Zeiger auf ein Objekt statt als globale Instanz definiert werden. Zur Laufzeit wird dann das Objekt dynamisch zugewiesen und wieder freigegeben.

 

Header-Dateien

Der Code von Headerdateien wird innerhalb eines #if-Präprozessorstatements gestellt:

#ifndef __FILENAME_H__
#define __FILENAME_H__
...
Code
...
#endif // __FILENAME_H__

Es muß immer der Dateinamen eingesetzt werden.

Werden Headerdateien mittels ‘#include’ eingebunden, muß zwischen Standard-Headerdateien und Projekt-Headerdateien unterschieden werden. Bei Standarddateien wird der Dateinamen zwischen Klein-Größer-Zeichen geschrieben, bei Projektdateien in Hochkomma. Außerdem dürfen Include-Anweisungen nur zu Beginn einer Datei stehen (bzw. als erste Abschnitt nach dem Header)

z.B.

/*s---------------------------------------------------------------------
   Include Files
----------------------------------------------------------------------*/
#include "prjfile.h"
#include <stdfile.h>

 

Kommentare

Kommentare sollten an jede sinnvolle Stelle gesetzt werden und den folgenden Programmablauf erklären, aber nicht wiederholen. Kommentare besitzen mindestens 3 Zeilen und haben folgendes Aussehen:

//
// Kommentar...
//

oder

//
// Kommentar Zeile 1
// Kommentar Zeile 2
//

Kommentare werden immer bis zum aktuellen Block eingerückt (siehe dazu Beispiel in Abschnitt ‘Blöcke’).

 

Mehrfach-Deklarationen

Wenn mehrere Deklarationen mit Zeigern und Referenzen vorhanden sind, müssen diese folgendermaßen formuliert werden:

UInt32_t* a;
UInt32_t* b;
UInt32_t* c;

und nicht

UInt32_t* a,
* b,
* c;

und ganz bestimmt nicht so:

UInt32_t* a, * b, * c;

 

 

Modulkopf

Jedes Quellcodemodul beginnt mit folgendem Header:

/*h----------------------------------------------------------------------
   Copyright (c)1998 Cynex. All rights reserved.
   $Archive: $
   $Revision: $
   $Author: $
   $Date: $
   Compiler: (1)
   Contents: (2)
   $NoKeywords: $
------------------------------------------------------------------------*/

Folgende Teile sind vom Programmierer auszufüllen:

(1) Der benötigte Compiler für diese Datei. Spezielle, compilerspezifische Eigenschaften werden ebenfalls hier vermerkt. z.B. Borland C++ (ab Version 4.0).

(2) Kurze Beschreibung des Inhalts der Source-Code Datei.

Die restlichen Einträge werden von der Versionkontrolle errweitert.

Eine in die Versionskontrolle archivierte Datei würde folgenden Header besitzen:

Beispiel:

/*h-----------------------------------------------------------------------
   Copyright (c)1998 Cynex. All rights reserved.
   $Archive: /PC/Systemkern/Quellcode/Imagine-Header/cynex.h $
   $Revision: 3 $
   $Author: Alexb $
   $Date: 30.08.96 17:47 $
   Compiler: C/C++
   Contents: General definitions for all Cynex projects. This header
             includes several other files
   $NoKeywords: $
------------------------------------------------------------------------*/

 

Zeiger und Referenzen

Zeiger und Referenzen gehören zu den Typen, nicht zur Variablen. Also:

int* j;
double& xAlias = x;

und nicht

int *j;
double &xAlias = x;

 

 

Bezeichnungskonventionen

Datentypen

Unter Datentypen sind einfache Typen, zusammengesetzte Typen und Klassen zusammengefaßt. Die Bezeichnung beginnen mit großem Anfangsbuchstaben. Besteht die Bezeichnung aus mehrere Wörtern, beginnt jedes Wort wiederum mit einem Großbuchstaben. Das Zeichen ‘_’ sollte innerhalb der Names nicht benutzt werden.

Außerdem besitzen Datentypen je nach Verwendung bestimmte Endungen:

Datentypendungen
Datentyp Endung Beispiel
Einfacher Datentyp _t UInt16_t
Zusammengesetzter Datentyp _s Component_s
Klassen _c SerialCommunication_c

 

Exportierte Funktionen

Funktionen, die von einer DLL exportiert werden, müssen ein definiertes Format vorweisen:

Jede exportierte Funktion muß als Rückgabewert den Typ Retcode_t benutzen. Die möglichen Fehlercodes sind in der Headerdatei ‘errdefs.h’ definiert.

 

Makros

Makros bestehen nur aus Großbuchstaben. Sollte sich ein Makronamen aus mehreren Wörtern zusammensetzen, muß zur Trennung das Zeichen ‘_’ verwendet werden. Globale Makros (z.B. Compilerdefinitionen) müssen vorne und hinten zwei ‘_’ besitzen (z.B. __MIDL_PASS__).

 

Ressourcen

Die Ressourcen eines Programms müssen durch ID’s bezeichnet werden. Folgende Tabelle zeigt die Präfixe der ID-Definitionen für verschiedenen Ressourcetypen:

Beginn der Bezeichner für Ressourcen
Ressourcentyp Präfix
Menütasten-Kürzel IDA_
Bitmap oder DIB IDB_
Cursor IDC_
Dialog IDD_
Schriftart IDF_
Symbol IDI_
Menü IDM_
String IDS_
Versions-Info IDV_
Hilfe IDH_
Benutzerdefiniert IDU_
Befehle CM_

 

Variablen

Variablen beginnen mit kleinem Anfangsbuchstaben und müssen immer den Zweck beschreiben (also keine Variablennamen wie ‘x’ oder ‘a’). Bei zusammengesetzten Namen wird ein neues Wort mit Großbuchstaben begonnen (außer natürlich der erste Buchstabe). Das Zeichen ‘_’ darf nicht zur Trennung der Worte verwendet werden.