C ist eine prozedurale Sprache für die Systemprogrammierung. Ein Übersetzer erzeugt optimierten Maschinencode für eine bestimmte Hardware-Architektur.
Datum | Version | Neuerungen |
1972 | NB | Urversion aus den Bell Labs |
1978 | K&R C | The C Programming Language, 1st edition |
1989 | ANSI C89 | Aufzählungen, Zuweisung von Strukturen |
1994 | ANSI C95 NA1 | Internationalisierung, Multibyte Zeichenketten |
2000 | ANSI C99 | Reihungen mit variabler Länge, Designierte Initialisierer |
2011 | ANSI C11 | Threads |
2018 | ANSI C17 | Keine |
hello.c#include <stdio.h> int main (int argc, char * argv[]) { if (argc == 1) { printf ("Hello, World!\n"); } else for (int i = 1; i < argc; i++) { printf ("Hello, %s!\n", argv[i]); } return 0; }
Übersetzen und ausführen mit:
gcc -std=c11 -o hello hello.c && ./hello Hello, World!
Der Quellcode für ein C-Programm oder Modul (Übersetzungseinheit) besteht aus:
Der Präprozessor (cpp
) expandiart Makros nach folgenden Regeln,
bevor der Übersetzer (cc
) den Code sieht:
Direktive | Parameter | Beschreibung | |
---|---|---|---|
Header | |||
#include | <File> | Datei aus Include-Pfad einbinden | |
#include | "File" | Datei aus Arbeitsverzeichnis einbinden | |
Makro | |||
#define | Name | Value | Konstante durch Wert ersetzen |
#define | Name(...) | __VA_ARGS__ | Variadisches Makro definieren |
#define | Name(Param, Args ...) | Args | Makro mit benannter Argumentliste |
#define | Name(Param) | #Param | Parameter stringifizieren |
#define | Name(Param) | ## Param | Parameter konkatenieren |
#undef | Name | Definition entfernen | |
Block | |||
#ifdef | Name | Block expandieren, wenn Konstante existiert | |
#ifndef | Name | Block expandieren, wenn Konstante fehlt | |
#if | Expression | Block expandieren, wenn Ausdruck wahr ist | |
#elif | Expression | Weitere Bedingung prüfen | |
#else | Alternative | ||
#endif | Blockende | ||
Implementierung | |||
#line | Number | Mitgeführte Zeilennummer ändern | |
#line | Number "File" | Mitgeführten Dateiname ändern | |
#error | MESSAGE | Übersetzer mit Fehlermeldung stoppen | |
Konstanten | |||
__FILE__ | Aktueller Dateiname | ||
__LINE__ | Aktuelle Zeilennummer | ||
__func__ | Name der aktuelle Funktion | ||
__DATE__ | mmm dd yyyy | Aktuelles Datum | |
__TIME__ | hh:mm:ss | Aktuelle Uhrzeit | |
__STDC__ | 1 | Standardkonformität des Übersetzers |
Konstante | Wert | Beschreibung | |
---|---|---|---|
__STDC__ | 1 | Übersetzer ist standardkonform | |
0 | Übersetzer nicht standardkonform | ||
__STDC_VERSION__ | Version des C Standards | ||
199409L | C95 | ||
199901L | C99 | ||
201112L | C11 | ||
__STDC_HOSTED__ | 1 | Betriebsystem vorhanden | |
0 | Kernelprogrammierung |
Die Deklaration einer Variable legt Speicherklasse, Zugriff, Vorzeichen, Größe, Typ, Name und den initialen Wert fest.
Speicherklasse | Zugriff | Vorzeichen | Größe | Typ | Bits | Literal |
auto register extern static thread_local |
const volatile restrict |
void |
||||
_Bool |
1 | true , false |
||||
signed unsigned |
char |
8 | 'A' |
|||
short long |
int |
16/32/64 | 0 |
|||
_Complex _Imaginary |
double |
64/80 | 0.1 |
|||
float |
32 | 0.1f |
int
) mit minimaler Größeint
) mit maximaler Größe oder Gleitkommazahl mit maximaler Genauigkeittrue
und false
annehmen.Primitive, Aufzählungen, Alternativen, Strukturen und Funktionen bevölkern jeweils einen eigenen Namensraum. Daher kann man gleiche Namen für verschiedene Klassen verwenden. Sprich: Eine Struktur kann genauso heißen wie eine Aufzählung.
Type Name = Value;
enum Name { Name = Value, … };
union Name { Type Name, … };
struct Name { Type Name, … } = { .Name = Value, … };
Type Name[Size] = { Value, … };
Type Name[Size][Size]… = { {… Value, …}, …};
Einen zusammengehörenden Bereich im Speicher bezeichnet man als Objekt. Der Übersetzer führt Buch über den Typ dieser Objekte, etwa ob es sich um eine Ganzzahl, eine Datenstruktur oder um eine Funktion handelt.
Eine Funktion ist ein Objekt, dessen Adresse man als Zeiger speichern, als Element in Strukturen verwenden oder als Parameter und Rückgabewert anderen Funktionen übergeben kann.
Type Name (Argument, …) { Statement; … }
Schlüsselwörter für Funktionen
inline
static
_Noreturn
void
-Funktionen.Die Präzedenz der Operatoren ist auf intuitive Verwendung ausgelegt, so dass man häufig auf Klammern verzichten kann. Geklammerte Ausdrücke genießen immer Vorrang, gefolgt von Index-Angaben in Reihungen, Zeiger-Dereferenzierung und Feldzugriffe. In arithmetischen Ausdrücken werden zuerst unäre Operatoren, dann Multiplikation, Addition und schließlich Bitoperationen ausgewertet. Danach folgen logische Ausdrücke mit Vergleich, Bitverknpüfung, Wahrheitslogik und Entscheidungslogik mit dem ternären Operator. Am geringsten binden Zuweisungen.
Operator | |||||||||||
Klammerausdrücke | () | [] | -> | . | |||||||
Unäre Operatoren | ! | ~ | ++ | -- | + | - | * | & | (Type) | sizeof | |
Multiplikation | * | / | % | ||||||||
Addition | + | - | |||||||||
Bitverschiebung | << | >> | |||||||||
Vergleich | < | <= | > | >= | == | != | |||||
Bitverknüpfung | & | ^ | | | ||||||||
Logisches UND/ODER | && | || | |||||||||
Ternärer Operator | ? … : | ||||||||||
Zuweisung | = | += | -= | *= | /= | %= | &= | ^= | |= | <<= | >>= |
Separator | , |
if (Condition) { … } else { … }
switch (Name) { case Value: … break; default: … break; }
for (Expression; Condition; Expression) …
while (Condition) …
do … while (Condition);
continue;
break;
goto Label;
return Expression;
asm { Instruction … }
Ein Zeiger ist eine Variable, welche die Speicheradresse eines Objekts enthält.
Type * Name = NULL;
Type (* Name) (Argument, …);
Type (* Name[Size]) (Argument, …);
Quelltext dient in erster Linie der Kommunikation mit anderen Entwicklern. Er sollte daher leicht zu verstehen und leicht zu erweitern sein. Es ist die Aufgabe des Übersetzers, daraus für den Rechner optimierte Anweisungen zu erzeugen.
Programme sollte wie Bücher aufgebaut sein:
Module fassen Datenstrukturen und alle darauf arbeitenden Funktionen zusammen.
if
-Blocks).einen wahren Wegbewahren.