2. Zeichen, Zeichensätze und Tokens

2.1. Zeichen

Ein C-Programm ist eine Folge von Zeichen aus einem Zeichensatz. Üblicherweise werden dabei folgende Zeichen verwendet:

    1. Die 52 Groß- und Kleinbuchstaben:
         A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
         a b c d e f g h i j k l m n o p q r s t u v w x y z

    2. Die 10 Ziffern:
         0 1 2 3 4 5 6 7 8 9

    3. Das Leerzeichen

    4. Der horizontaler und der vertikaler Tabulator sowie der Seitenvorschub

    5. Die folgenden 29 Zeichen:
         ! " % & ( ) = . , : ; + - * / # ~ { } [ ] < > | ’ _ \ ? ^

Zusätzlich wird ein Zeichen oder eine Zeichenfolge benötigt, die das Ende der Programmzeilen angibt. Alle weiteren Zeichen (z.B. für die Formatierung des Quelltextes) werden als Leerzeichen angesehen und beeinflussen den Quelltext in keiner Weise.

2.2. Zeichensatz im ausführenden Programm

Der Zeichensatz, der für das Programm während der Ausführung verwendet wird, muss nicht identisch sein mit dem Zeichensatz, der für die Eingabe der Quelltexte verwendet wird. Daher kann es bei der Ein- und Ausgabe zu unerwünschten Effekten kommen. So werden z.B. bei einem Konsolen-Programm, das unter MS Windows eingegeben und in einem DOS-Fenster ausgeführt wird, die deutschen Umlaute in der Bildschirmausgabe nicht korrekt angezeigt.

Um diese Probleme zu umgehen, müssen diese Zeichen als ASCII-Werte (oktal) in den Quelltext eingegeben werden.

Beispiel:

kap02_01.c

01 #include <stdio.h>
02
03 int main()
04 {
05    printf("Deutsche Umlaute\n\n");
06
07    printf("Linux-Konsole (ISO-8859):\n");
08    printf("ae = \344\n");
09    printf("oe = \366\n");
10    printf("ue = \374\n\n");
11
12    printf("DOS-Eingabeaufforderung:\n");
13    printf("ae = \204\n");
14    printf("oe = \224\n");
15    printf("ue = \201\n\n");
16
17    return 0;
18 }


2.3. Weiße Leerzeichen und Zeilenende

In einem C-Programm werden das Leerzeichen, das Zeilenende, der horizontale und der vertikaler Tabulator und der Seitenvorschub als Weiße Leerzeichen (White Spaces) bezeichnet. Auch Kommentare werden wie weiße Leerzeichen behandelt (siehe Abschnitt Kommentare). Diese Zeichen werden ignoriert, da sie nur zum Trennen von benachbarten Tokens dienen - mit Ausnahme, wenn diese Zeichen in konstanten Zeichen bzw. Zeichenketten stehen.

Weiße Leerzeichen werden im allgemeinen verwendet, um ein C-Programm für uns Menschen lesbarer zu machen (siehe Kapitel Gestaltung von C-Programmen).

Das Zeilenende-Zeichen bzw. -Zeichenfolge markiert das Ende einer Quelltextzeile. Manche C-Compiler interpretieren die Eingabetaste, den Seitenvorschub und den vertikalen Tabulator auch als Ende einer Quelltextzeile. Dies ist wichtig für das Erkennen, wann eine Präprozessorzeile (siehe Kapitel Präprozessorbefehle) zu Ende ist.

Eine Quelltextzeile kann in der nächsten Editor-Zeile fortgeführt werden, wenn sie mit einem Backslash ('\') oder mit dem Trigraph '??/' (siehe nächsten Abschnitt Trigraphen) beendet wird. Im C99-Standard lassen sich damit sogar Tokens aufsplitten. Beim Compilieren wird der Backslash bzw. der Trigraph samt Zeilenende beseitigt, um eine längere, logisch zusammenhängende Zeile zu erzeugen. Dies geschieht nach dem Konvertieren der Trigraphen und der Multibyte-Zeichen, aber noch vor dem Präprozessor und dem eigentlichen Compiliervorgang.

Beispiel:

Die Zeilen

if (a == b) x = 1; el\
se x = 2;

werden umgewandelt in

if (a == b) x = 1; else x = 2;

Viele C-Compiler lassen nur eine bestimmte Länge für die Quelltextzeilen - vor und nach dem Umwandeln - zu. Der C89-Standard erlaubt logische Zeilen bis maximal 509 Zeichen, der C99-Standard bis maximal 4.095 Zeichen.

2.4. Trigraphen

Mit dem Standard-C wurden einige Zeichenfolgen eingeführt, mit denen wichtige Zeichen dargestellt werden können, auch wenn der Quelltext mit einem Zeichensatz geschrieben wird, der diese Zeichen nicht beinhaltet. Da diese Zeichenfolgen immer aus drei Zeichen bestehen, werden diese auch Trigraphen genannt. Trigraphen werden auch in konstanten Zeichenfolgen erkannt und umgesetzt. Das Umwandeln der Trigraphen erfolgt beim Aufruf des Compilers als erstes, sogar noch vor dem Präprozessor. Es gibt genau neun Trigraphen, alle anderen Zeichenfolgen, die mit zwei Fragezeichen beginnen, werden nicht verändert.

Trigraph   Ersetzt         Trigraph   Ersetzt


??( [   ??) ]
??< {   ??> }
??/ \   ??! |
??' ^   ??- ~
??= #      

Beispiel:

Um eine konstante Zeichenfolge mit einem Backslash auszugeben, müssen zwei aufeinander folgende Backslashs geschrieben werden. Jeder dieser Backslash kann wieder in einen Trigraphen umgesetzt werden. Daher wird mit der Zeichenfolge "??/??/" ein Backslash "\" ausgegeben.

Um zu verhindern, dass eine Zeichenfolge als Trigraph interpretiert wird, muss das zweite Fragezeichen durch '\?' ersetzt werden. Um die Zeichenkette "Wer??!" zu erhalten, muss also "Wer?\?!" eingegeben werden.

kap02_02.c

01 #include <stdio.h>
02
03 int main()
04 {
05    printf("Trigraphen:\n\n");
06
07    printf("Backslash: ??/??/\n");
08    printf("Wer??!   oder   Wer?\?!\n");
09
10    return 0;
11 }

Bei manchen Compiler muss explizit angegeben werden, dass Trigraphen verwendet werden. Zum Beispiel muss beim GNU-C-Compiler gcc zusätzlich die Option -trigraphs angegeben werden.

2.5. Multibytes und Wide Characters

Mit C95 wurden die Multibytes und Wide Characters eingeführt. Damit können auch Zeichensätze verwendet werden, die mehr als 256 Zeichen beinhalten. Auf diese speziellen Zeichen wird im Kapitel Datentypen in C weiter eingegangen.

2.6. Kommentare

Kommentare werden vom Compiler komplett ignoriert, d.h. sie werden wie weiße Leerzeichen behandelt. Kommentare sollen zum Verständnis des Quelltextes dienen bzw. dem Leser wichtige Hinweise geben.

Ein Kommentar beginnt mit den zwei Zeichen /* und endet mit den zwei Zeichen */. Dazwischen können beliebig viele Zeichen - einschließlich Zeilenumbrüche - stehen. Im Standard-C können Kommentare nicht geschachtelt werden.

In C99 wurden zusätzlich Zeilenkommentare eingeführt. D.h. ein Kommentar kann auch mit // beginnen. Dieser Kommentar endet dann automatisch am Ende der Zeile.

Kommentare werden nicht innerhalb von konstanten Zeichen oder Zeichenketten - also innerhalb von Anführungszeichen - erkannt.

Kommentare werden noch vor dem Präprozessor entfernt, so dass Präprozessorbefehle innerhalb von Kommentaren nicht erkannt werden können. Auch haben Zeilenumbrüche innerhalb von Kommentaren keinerlei Auswirkungen auf die Programmzeile, in der der Kommentar steht.

Standard-C schreibt vor, dass alle Kommentare durch ein einzelnes Leerzeichen ersetzt werden sollen. Einige ältere Compiler löschen wohl die Kommentare, aber setzen dafür kein Leerzeichen ein. Dies kann fatale Folgen haben, da ohne Leerzeichen die Texte vor und hinter dem Kommentar nahtlos zusammengeschrieben werden.

Kommentare sollten nicht dafür genutzt werden, um größere Programmteile auszukommentieren. Denn ist in diesem Programmteil selber wieder ein Kommentar (geschachtelte Kommentare; siehe oben), wird nicht wirklich das ganze Programmteil auskommentiert. Ein Compilerfehler ist die Folge.

2.7. Tokens

Die Zeichen, aus denen das C-Programm besteht, werden in sogenannten Tokens unterteilt. Es gibt fünf Gruppen von Tokens: Operatoren, Trennzeichen, Bezeichner, Schlüsselwörter und Literale.

Benachbarte Tokens werden am besten durch weiße Leerzeichen getrennt. Vor und nach Operatoren müssen keine weißen Leerzeichen stehen; der Compiler setzt dann von links nach rechts immer die längstmöglichen Tokens zusammen, auch wenn das Ergebnis kein gültiges C-Programm mehr ist. Von daher sollten auch hier weiße Leerzeichen verwendet werden.

Beispiele:

In der folgenden Tabelle werden verschiedene Zeichenfolgen und deren Erkennung in C-Tokens dargestellt. Dabei werden die einzelnen erkannten C-Tokens mit einem Komma getrennt.

Zeichenfolge     C-Tokens

forwhile forwhile
b>x b, >, x
b->x b, ->, x
b--x b, --, x
b---x b, --, -, x

Im ersten Beispiel werden die Schlüsselwörter for und while nicht als einzelne Tokens erkannt, da sie nicht mit einem weißen Leerzeichen getrennt wurden.

Das vierte Beispiel erzeugt einen Fehler beim Compilieren, da hier die Tokens falsch erkannt werden. Richtig erkannt werden sie erst mit dem Einsetzen von weißen Leerzeichen: b - -x. Dann wird nämlich das erste Minuszeichen als Operator für die Subtraktion und das zweite Minuszeichen als Vorzeichen für die Variable x erkannt.

Das fünfte Beispiel ist für den Leser nicht klar: Es kann   b-- - x   oder   b - --x   gemeint sein. Erst durch die Regel, dass von links nach rechts immer die längstmöglichen Tokens erkannt werden, macht klar, dass der Compiler tatsächlich die erste Variante erkennt. Wird die zweite Variante gewünscht, müssen entsprechende weiße Leerzeichen eingefügt werden.

2.8. Operatoren und Trennzeichen

Die im Standard-C gültigen Operatoren und Trennzeichen sind in der folgenden Tabelle aufgelistet. Um Programmierer zu unterstützen, deren Tastatur die geschweiften und eckigen Klammern und die Raute (#) nicht enthalten, können auch die alternativen Schreibweisen verwendet werden: <%, %>, <:, :>, %: und %:%:.

Im traditionellen C werden die zusammengesetzten Zuweisungsoperatoren als zwei seperate Tokens erkannt - nämlich als Operator und als Gleichheitszeichen. Hier dürfen also auch weiße Leerzeichen zwischen Operator und Gleichheitszeichen verwendet werden. Im Standard-C dagegen werden die zusammengesetzten Zuweisungsoperatoren als ein einzelnes Token erkannt; entsprechend dürfen im Standard-C keine weißen Leerzeichen zwischen Operator und Gleichheitszeichen eingefügt werden.

Bezeichnung Tokens

Einzelne Operatoren ! % ^ & * - + =
~ | . < > / ?
Zusammengesetzte
Zuweisungsoperatoren
+= -= *= /= %= <<=
>>= &= ^= |=
Andere zusammengesetzte    
Operatoren
-> ++ -- << >> <=
>= == != && ||
Trennzeichen ( ) [ ] { } , ; : ...
Alternative Schreibweise
für Trennzeichen
<%     (geschweifte Klammer auf)
%>     (geschweifte Klammer zu)
<:     (eckige Klammer auf)
:>     (eckige Klammer zu)
%:     (Raute)
%:%:   (zwei Rauten hintereinander)

Beispiel:

kap02_03.c

01 %:include <stdio.h>
02
03 int main()
04 <%
05    int Array<:10:> = <% 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 %>;
06
07    printf("Array[5] = %i\n", Array<:5:>);
08
09    return 0;
10 %>

Die alternativen Schreibweisen für Trennzeichen werden nicht von allen Compilern unterstützt.

2.9. Bezeichner

Bezeichner sind Namen für Konstanten, Variablen, Datentypen, Klassen, Funktionen oder Makros. Sie bestehen aus einer Folge von Buchstaben, Ziffern und dem Unterstrich; sie dürfen allerdings nicht mit einer Ziffer beginnen und dürfen keine Schlüsselwörter sein. Dabei wird bei den Buchstaben zwischen Groß- und Kleinschreibung unterschieden, d.h. die Bezeichner abc und ABC sind zwei unterschiedliche Bezeichner.

Seit C99 dürfen Bezeichner auch andere universelle oder systemabhängige Multibyte-Zeichen beinhalten. Diese dürfen wie die Ziffern nicht als erstes Zeichen verwendet werden und müssen ähnlich wie Buchstaben sein. Eine Liste der für Bezeichner erlaubten Zeichen ist im C99-Standard ISO/IEC 9899: 1999 und im ISO/IEC TR 10176-1998 zu finden. Darauf wird in diesem Skript nicht weiter eingegangen.

Neben den Schlüsselwörtern muss man aufpassen, nicht einen Bezeichner der Standard-Bibliotheken doppelt zu verwenden. Viele dieser Bezeichner fangen mit einem Unterstrich an, gefolgt von entweder einem zweiten Unterstrich oder einem Großbuchstaben. Daher sollten keine Bezeichner verwendet werden, die mit einem Unterstrich beginnen.

Während Bezeichner im Prinzip beliebig lang sein dürfen - sie dürfen maximal so lang sein, wie eine Programmzeile lang sein darf -, wird nur eine bestimmte (signifikante) Anzahl von Zeichen zur Unterscheidung der Bezeichner verwendet. Vor dem C89-Standard betrug sie manchmal nur 8 Zeichen (Compilerabhängig; schließlich gab es damals noch keinen Standard), im C89-Standard betrug sie mindestens 31 Zeichen und im C99-Standard mindestens 63 Zeichen.

Beispiel:

Vor dem C89-Standard waren für einen Compiler die beiden Bezeichner LangerBezeichner und LangerBezeichnerNeu identisch, da nur die ersten 8 Zeichen zur Unterscheidung verwendet wurden.

Für externe Bezeichner - also Bezeichner, die mit dem Schlüsselwort extern deklariert werden - gelten weitere Einschränkungen, da diese Bezeichner unter Umständen auch von anderen Compilern, Linkern oder Debugger, die stärkere Begrenzungen haben, bearbeitet werden müssen. So fordert der C89-Standard vom Compiler, dass externe Bezeichner eine maximale Länge von mindestens 6 Zeichen haben dürfen. Der C99-Standard hat dies auf mindestens 31 Zeichen erweitert.

2.10. Schlüsselwörter

Die Bezeichner, die in der folgenden Tabelle aufgelistet werden, sind Schlüsselwörter (engl. keywords) und dürfen anderweitig nicht als Bezeichner (z.B. als Variablen) verwendet werden. Schlüsselwörter dürfen aber als Präprozessor-Makronamen verwendet werden, da der Präprozessor diese Makronamen umsetzt bevor der Compiler mit der Erkennung der Schlüsselwörter beginnt.

auto _Bool 1 break case char _Complex 1  
const continue     default     do double else
enum extern float for goto if
_Imaginary 1     inline 1 int long register     restrict 1  
return short signed sizeof static struct
switch typedef union unsigned     void volatile
while

1 Diese Schlüsselwörter sind erst im C99-Standard enthalten. Davon ist aber nur das Schlüsselwort inline auch in C++ ein Schlüsselwort!

Mit dem C11-Standard sind noch folgende Schlüsselwörter dazu gekommen:

_Alignas _Alignof _Atomic _Generic
_Noreturn     _Static_assert     _Thread_local      

Zusätzlich haben einige Compiler als Spracherweiterung die Schlüsselwörter asm (Schlüsselwort in C++) und fortran. Ferner sind in der Headerdatei iso646.h die Makros and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor und xor_eq definiert, die in C++ zu den Schlüsselwörter gehören.

2.11. Literale

Es gibt vier verschiedene Arten von Literalen (engl. literals): Ganze Zahlen, Fließkommazahlen, Zeichen und Zeichenketten. Manchmal werden Literale auch fälschlicherweise "Konstante" genannt; sie müssen aber von den unveränderlichen Variablen, Konstanten und Datentypen unterschieden werden.

Jedes Literal ist gekennzeichnet durch Wert und Datentyp. Die Formate der verschiedenen Literale werden im Kapitel Datentypen in C vorgestellt.



Voriges Kapitel: 1. Einführung