Deklarationen in C

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

C Deklarationen können, wenn sie umfangreicher sind, ganz schön kompliziert sein. Zumindest sieht es auf den ersten Blick so aus. Aber es gibt Abhilfe: Es gibt ein Regelwerk, nach dem man Deklarationen, egal wie kompliziert sie sind, in einen leidlich deutschen Satz 'übersetzen' kann.

Die vollständige Rechts-Links Regel

Die Anwendung der Rechts-Links Regel gestattet eine C Deklaration in einen lesbaren deutschen Satz zu übersetzen. Einige der Symbole werden durch feststehende Phrasen übersetzt. Diese sind

Phrase wird übersetzt mitAnmerkung
*"Zeiger auf" steht immer links
[]"Array von" steht immer rechts
()"Funktion welche zurückgibt" steht immer rechts

Schritt 1:

Der ganz Prozess wird immer ausgehend vom Variablennamen durchgeführt. Ihn gilt es als erstes zu finden. Hat man ihn, dann beginnt der deutsche Satz mit "xyz ist ein"

Schritt 2:

Ausgehend vom Variablennamen beginnt man abwechselnd rechts / links weiter zu lesen, wobei man mit der rechten Seite beginnt. Es wird immer solange in eine Richtung weiter gelesen, bis dort nichts mehr steht (bzw. ein ';' angetroffen wird) oder bis man auf eine schliessende Klammer ')' stösst. Genauso im umgekehrten Fall: ist die Leserichtung nach links, dann dreht sich diese um, wenn man auf eine öffnende Klammer '(' stösst.

Schritt 3:

Handelt es sich bei einem 'Wort' um eine entsprechende Phrase, so wird diese eingesetzt. Andernfalls setzt man einfach das angetroffene Wort ein.

Beispiele:

int *p[];

Als erster wird der Variablenname gesucht. In diesem Fall ist es das 'p'.

 int *p[];              p ist ein
      ^

nach rechts weiterlesen. Dort wird die Phrase [] angetroffen

 int *p[];              p ist ein Array von
       ^^

das nächste Zeichen in Leserichtung rechts ist ein ';'. Damit geht es da nicht mehr weiter, die Leserichtung wird umgedreht und es geht nach links weiter. Das nächste Zeichen ist der *

 int *p[]               p ist ein Array von Zeigern auf
     ^

wieder nach links weiterlesen, bringt das 'int' zutage, welches direkt übernommen wird.

 int *p[]               p ist ein Array von Zeigern auf int
 ^^^

Die Deklaration besagt also dass es sich um ein Array von Zeigern handelt und nicht etwa um einen Zeiger auf ein Array. Wie müsste so etwas aussehen? Ganz einfach. Der * steht immer auf der linken Seite des Variablennamens und die Array-Phrase rechts davon. Da immer mit der Leserichtung rechts begonnen wird, muss man nur dafür sorgen, dass sich die Leserichtung sofort umkehrt. Die einzige Möglichkeit, die es dafür gibt, ist die Benutzung von Klammern ( und ). (Achtung: diese Klammern nicht mit der ()-Phrase für Funktionen verwechseln! Es ist aber immer eindeutig, wann es sich um ein Klammernpaar handelt, welches eine Funktion anzeigt.) Wir möchten konstruieren: u ist ein Zeiger auf ein Array von double.

          u                 u ist ein
         *u                 u ist ein Zeiger
        (*u)[]              u ist ein Zeiger auf ein Array
                            man beachte an dieser Stelle, wie das Klammernpaar dafür
                            sorgt, dass sich die Leserichtung beginnend beim Variablennamen
                            sofort umdreht, so dass zuerst der * relevant wird und erst dann
                            die [] zum Zug kommen.
 double (*u)[]              u ist ein Zeiger auf ein Array von double

Mit der Kentniss der Rechts/Links Regel ist es also nicht nur möglich eine Deklaration zu lesen, sondern auch Deklarationen zu konstruieren. Sie leitet durch die Deklaration und lässt eine Aussage darüber zu, wo Klammern Paare ( ) die Interpretation verändern.

int *(*func())();

   int *(*func())();         func ist ein
          ^^^^
   int *(*func())();         func ist eine Funktion, die zurückgibt
              ^^
                             Das nächste Symbol in Leserichtung rechts ist eine ),
                             also dreht sich die Leserichtung um und es geht links weiter
   int *(*func())();         func ist eine Funktion, die einen Pointer zurückgibt
         ^
                             In Leserichtung links ist das nächste Symbol eine (,
                             also dreht sich die Leserichtung wieder um und es geht rechts
                             nach der ) weiter.
   int *(*func())();         func ist eine Funktion, die zurückgibt einen Pointer auf
                 ^^          eine Funktion
   int *(*func())();         func ist eine Funktion, die zurückgibt einen Pointer auf
       ^                     eine Funktion, welche zurückgibt einen Pointer
 
   int *(*func())();         func ist eine Funktion, die zurückgibt einen Pointer auf
   ^^^                       eine Funktion, welche zurückgibt einen Pointer auf int

Besonderheiten

mit Arrays

Steht in einer Arraydeklaration eine Größenangabe in den [], so kann man diese Größenangabe in die Beschreibung mit heineinnehmen. Grundsätzlich ändert sich aber an der Verwendung der []-Phrase nichts.

   int p[5];                 p ist ein
       ^
   int p[5];                 p ist ein Array der Größe 5
        ^^^
   int p[5];                 p ist ein Array der Größe 5 von int
   ^^^

mit Funktionen

Sind in der ()-Phrase die Datentypen der Funktionsargumente angegeben, so werden diese bei der Funktion als "welche erwartet ...." aufgeführt. Aber auch hier wieder: an der grundsätzlichen Verwendung der ()-Phrase ändert sich nichts

Beispiele:

 int (*(*foo)(char *, double))[5][4];

foo ist ein Zeiger auf eine Funktion, welche einen char* und einen double erwartet und welche zurückgibt einen Zeiger auf ein Array der Größe 5 eines Arrays der Größe 4 von int.

(Zugegeben: der deutsche Satz holpert ein wenig, aber mit ein wenig umstellen, kann man ihn leicht in ordentliches Deutsch überführen)

Besonderheiten für Modifizierer wie const oder volatile

Diese Phrasen werden ganz normal in den Text eingebaut. Dabei gilt: Diese Modifizierer gelten immer auf den nächsten Abschnitt links von ihnen. Es sei denn, sie stehen bereits ganz links, dann gelten sie auf den Teil rechts von ihnen.

    int  i;          i ist ein int
    int const i;     i ist const und dieses konstante ist ein int
    const int i;     i ist ein int und dieser int ist const (ist dasselbe wie int const i)
    int * v;         v ist ein Zeiger auf int
    int * const v    v ist konstant und ist ein Zeiger auf int (Der Zeiger ist konstant!)
    int const * v    v ist ein Zeiger auf etwas konstantes und dieses konstante ist ein int
                     (hier ist der int auf den der Zeiger zeigt konstant!)
    const int * v    v ist ein Zeiger auf einen int und dieser int ist konstant.
                     (identisch zum vorhergehenden Fall: der int ist konstant!)
    const int * const v   v ist ein konstant und ist ein Zeiger auf einen int, der konstant ist
                     (hier sind also sowohl Zeiger als auch der int konstant)

Weblinks