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
Nächstes Kapitel: 3. Variablen