Menu

C-Syntax: Der Aufbau eines C-Programms erklärt

Jedes C-Programm hat dasselbe Grundgerüst: Includes, eine main-Funktion, Anweisungen mit Semikolon und Blöcke in geschweiften Klammern. Hier steht, was jeder Teil tut und welche Regeln der Compiler tatsächlich durchsetzt.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

C hat sehr wenig Syntax zu lernen - etwa 32 Schlüsselwörter und eine Handvoll Zeichenregeln. Fast jedes Programm, das du je schreiben wirst, hat dieselbe äußere Form, also lohnt es sich, diese Form einmal gründlich auseinanderzunehmen.

Das kleinste vollständige Programm

Das hier kompiliert, läuft und tut nichts:

Keine Includes, keine Ausgabe, keine Pflichtklasse und kein Modulgerüst. main ist der Einstiegspunkt: Wenn das Betriebssystem dein Programm startet, ruft es main auf. Wenn main zurückkehrt, endet das Programm, und der zurückgegebene Wert ist der Exit-Status.

Füge Ausgabe hinzu, und du brauchst ein Include:

Präprozessor-Direktiven

Zeilen, die mit # beginnen, werden vor der eigentlichen Übersetzung vom Präprozessor behandelt. Sie sind keine C-Anweisungen und bekommen kein Semikolon.

#include <stdio.h>    /* Header der Standardbibliothek - spitze Klammern */
#include "myutils.h"  /* eigener Header - Anführungszeichen, zuerst lokal gesucht */
#define MAX 100       /* ein Makro - MAX wird unten überall durch 100 ersetzt */

#include ist ein wörtliches Einfügen von Text: Der gesamte Inhalt der genannten Datei wird an dieser Stelle eingesetzt. stdio.h enthält die Deklaration von printf, und dadurch weiß der Compiler, welche Argumente printf entgegennimmt. Lass das Include weg, und du bekommst implicit declaration of function 'printf'.

Der Unterschied zwischen spitzen Klammern und Anführungszeichen betrifft, wo der Compiler sucht: <...> meint die System-Include-Verzeichnisse, "..." bedeutet, zuerst neben dieser Datei nachzusehen.

Die main-Funktion

int main(void) {
    return 0;
}

Vier Teile, jeder mit Bedeutung:

  • int - der Rückgabetyp von main. Der Wert geht als Exit-Status an das Betriebssystem, wobei 0 Erfolg bedeutet.
  • main - der reservierte Name, den die Laufzeit aufruft. Jedes gehostete C-Programm hat genau eine.
  • (void) - die Parameterliste. void bedeutet hier „nimmt keine Argumente entgegen". Stattdessen main() zu schreiben ist erlaubt, aber schwächer: Leere Klammern bedeuten in C „nicht spezifizierte Parameter", was die Argumentprüfung abschaltet.
  • { ... } - der Funktionsrumpf.

Die andere Standardform nimmt Kommandozeilenargumente entgegen:

int main(int argc, char *argv[]) { ... }

Verwende int main(void), bis du sie brauchst.

Anweisungen und Semikolons

Eine Anweisung ist eine einzelne Instruktion, und sie endet mit einem Semikolon.

Vier Anweisungen, vier Semikolons. Das Semikolon ist ein Abschlusszeichen, kein Trennzeichen - auch die letzte Anweisung eines Blocks braucht eines.

Was kein Semikolon bekommt:

#include <stdio.h>        /* Präprozessorzeile - kein Semikolon */

int add(int a, int b) {   /* Kopf einer Funktionsdefinition - kein Semikolon */
    return a + b;
}                         /* schließende Klammer einer Funktion - kein Semikolon */

if (x > 0) {
    ...
}                         /* schließende Klammer eines Blocks - kein Semikolon */

Der eine Fall, der jeden erwischt, ist ein Semikolon dort, wo ein Rumpf stehen sollte:

if (score > 90);                 /* BUG: dieses ; ist der ganze if-Rumpf */
    printf("Ausgezeichnet!\n");  /* läuft immer, egal wie score ist */

Das ist vollkommen gültiges C. Das if steuert eine leere Anweisung, und das printf ist einfach die nächste Zeile in der Reihenfolge. -Wall warnt davor; der Compiler hält dich nicht auf.

Blöcke und geschweifte Klammern

Geschweifte Klammern fassen Anweisungen zu einem Block zusammen, der überall dort als eine Anweisung zählt, wo eine Anweisung erwartet wird.

Klammern sind optional, wenn der Rumpf eine einzelne Anweisung ist, aber sie wegzulassen ist der Weg zu den berühmten Bugs - füge später eine zweite Zeile hinzu, und sie verlässt still das if. Setze immer Klammern.

Blöcke erzeugen außerdem Gültigkeitsbereiche: Eine innerhalb von { ... } deklarierte Variable existiert bei der schließenden Klammer nicht mehr.

Groß-/Kleinschreibung und Leerraum

C unterscheidet überall zwischen Groß- und Kleinschreibung. total, Total und TOTAL sind drei verschiedene Namen. Jedes Schlüsselwort ist kleingeschrieben, Int, Return und Printf sind also alle Fehler - und die Fehlermeldung für Printf ist verwirrend, weil der Compiler annimmt, du meintest irgendeine Funktion, von der er nie gehört hat.

Leerraum dagegen ist fast völlig frei. Der Compiler behandelt jede Folge aus Leerzeichen, Tabs und Zeilenumbrüchen als ein Trennzeichen. Das hier ist gültig:

int    main ( void )
{
    printf
    ( "Hallo\n" ) ;
    return 0 ;
}

Das hier auch:

int main(void){printf("Hallo\n");return 0;}

Beide kompilieren identisch. Da es dem Compiler egal ist, dient die Formatierung ausschließlich Menschen - und das übliche Layout (eine Anweisung pro Zeile, vier Leerzeichen oder ein Tab pro Verschachtelungsebene, öffnende Klammer in derselben Zeile) ist es wert, befolgt zu werden, weil jede C-Codebasis, die du liest, etwas Ähnliches verwenden wird.

Zwei Stellen, an denen Leerraum doch zählt: Du kannst ein Schlüsselwort oder einen Bezeichner nicht aufteilen (in t ist nicht int), und du kannst keinen Zeilenumbruch in ein normales Zeichenkettenliteral setzen.

Bezeichner: Namensregeln

Ein Bezeichner ist jeder Name, den du wählst - Variablen, Funktionen, Typen. Die Regeln:

  • Bestehen aus Buchstaben, Ziffern und Unterstrichen.
  • Dürfen nicht mit einer Ziffer beginnen. total2 ist in Ordnung, 2total nicht.
  • Dürfen kein Schlüsselwort sein: keine Variable namens int, for oder return.
  • Groß-/Kleinschreibung zählt.
  • Namen, die mit einem Unterstrich beginnen, und alles mit zwei aufeinanderfolgenden Unterstrichen sind für die Implementierung reserviert - erfinde sie nicht.
int score;        /* gut */
int total_items;  /* gut - snake_case ist die C-Konvention */
int _hidden;      /* erlaubt, aber reserviert - vermeiden */
int 2fast;        /* Fehler */
int float;        /* Fehler - Schlüsselwort */

Ein vollständig kommentiertes Programm

Alles von oben, an einer Stelle:

Die Lesereihenfolge zählt hier: with_tax ist definiert, bevor main es benutzt. C liest die Datei von oben nach unten, eine Funktion muss also deklariert sein, bevor sie aufgerufen wird. Definiere sie weiter oben, oder schreibe oben einen Funktionsprototyp und definiere sie später.

Häufig gestellte Fragen

Wie ist ein C-Programm grundsätzlich aufgebaut?

Zuerst Präprozessor-Direktiven (#include <stdio.h>), dann Funktionsdefinitionen, von denen eine main heißen muss. Innerhalb einer Funktion enden Anweisungen mit Semikolons und Blöcke stehen in geschweiften Klammern. Ein minimales Programm ist #include <stdio.h> plus int main(void) { return 0; }.

Warum heißt es int main(void) und nicht einfach main()?

int ist der Rückgabetyp von main - der Exit-Status, den das Programm an das Betriebssystem zurückgibt. (void) sagt ausdrücklich, dass main keine Argumente entgegennimmt. main() mit leeren Klammern ist ein älterer Stil, der dem Compiler nichts über die Parameter sagt, sodass er weniger prüft.

Brauchen alle C-Anweisungen ein Semikolon?

Jede Anweisung schon, aber nicht jede Zeile. Präprozessor-Direktiven (#include, #define), Funktionsdefinitionen und die schließende Klammer eines Blocks oder eines if/for/while bekommen keines. Ein verirrtes Semikolon nach if (x) ist gültiges C und lässt den Rumpf still bedingungslos laufen.

Unterscheidet C zwischen Groß- und Kleinschreibung?

Ja, vollständig. count, Count und COUNT sind drei verschiedene Bezeichner, und Int ist nicht das Schlüsselwort int. Jedes C-Schlüsselwort ist kleingeschrieben, ein Großbuchstabe in Return oder Printf erzeugt also einen Fehler.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S