Lesbarkeit und Stil
Neben Kommentaren bestimmen auch Formatierung und Konventionen die Verständlichkeit von C-Programmen. Compiler ignorieren Leerzeichen und Zeilenumbrüche weitgehend, doch für Menschen sind Einrückungen, Klammern und Leerzeilen entscheidend.
Einrückungen
Für den Menschen hingegen sind Einrückungen das wichtigste Hilfsmittel, um sofort die Struktur des Programms zu erkennen. Fehlende oder uneinheitliche Einrückungen erschweren das Verständnis erheblich und führen oft zu Fehlern beim Lesen oder Überarbeiten des Codes.
Der Compiler akzeptiert folgenden Quelltext ohne Beanstandung:
#include <stdio.h>
int main() { puts("Hello, world!"); } // ❌
Für Leser ist aber schwer erkennbar, wo die Anweisung puts("Hello, world!"); hingehört. Die Lösung besteht darin, logische Blöcke durch Einrückungen zu strukturieren. Im Normalfall wird der Block einer Funktion oder einer Kontrollstruktur (z. B. für Fallunterscheidungen und Schleifen) um eine Stufe eingerückt.
#include <stdio.h>
int main() {
puts("Hello, world!");
}
Ein weiterer Punkt für bessere Lesbarkeit ist die Regel: eine Zeile, eine Anweisung. Der Compiler erlaubt zwar mehrere Anweisungen in einer Zeile, doch der Code wird dadurch für Menschen schnell unübersichtlich.
#include <stdio.h>
int main() {
puts("Hello, world!"); puts("Hello, C!"); // ❌
}
Übersichtlicher und wartbarer ist es, jede Anweisung in eine eigene Zeile zu setzen und zusätzlich einzurücken:
#include <stdio.h>
int main() {
puts("Hello, world!");
puts("Hello, C!");
}
Tipp: Wende die Regeln konsequent an. Uneinheitliche Einrückungen oder mehrere Anweisungen in einer Zeile führen dazu, dass der Code widersprüchlich wirkt und Leser auf Nebensächlichkeiten achten müssen, statt der eigentlichen Programmlogik zu folgen.
Ein häufiger Diskussionspunkt ist die Wahl zwischen Tabulator und Leerzeichen. Technisch spielt das keine Rolle, solange ein Projekt konsequent bei einer Variante bleibt. Zwei oder vier Leerzeichen pro Ebene werden oft bevorzugt, da damit die Einrückung unabhängig von Tabulator-Einstellungen immer gleich aussieht. Moderne Code-Editoren bieten ohnehin automatische Formatierung an, sodass diese Frage heute meist über einen Projekt-Styleguide geregelt wird.
[cols="1,3", options="header"] |=== | Einrückung | Projekte (Beispiele) | 2 Leerzeichen | curl, GTK/GLib, TianoCore/EDK II, libxml2, libcurl, Mosquitto MQTT, json-c, libevent, libpng | 4 Leerzeichen | CPython, nginx, FFmpeg, OpenSSL, Apache httpd, SQLite, Redis, memcached, zlib, libssh2, ImageMagick, GStreamer, libjpeg-turbo | Tabs (Tabstop = 8) | Linux-Kernel, Git, PostgreSQL, OpenBSD, FreeBSD, NetBSD, Vim, Emacs, busybox, OpenWrt, U-Boot, QEMU | 8 Leerzeichen | systemd, GNU Coreutils, GNU Compiler Collection (GCC), GNU Make |===
Tabelle: Beispiele für Einrückungsstile in großen C-Projekten
Klammerstil
Neben der Einrückung prägt auch die Position der geschweiften Klammern die Lesbarkeit. Der Compiler ist dabei völlig flexibel und akzeptiert verschiedene Schreibweisen ohne Unterschied in der Bedeutung.
Ein weitverbreiteter Stil ist K&R (nach Kernighan und Ritchie), bei dem die öffnende Klammer am Ende der Einleitungszeile steht. Diesen Stil nutzen wir auch hier im Buch.
int main() {
if (…) {
…
}
}
Demgegenüber steht der Allman-Stil, benannt nach Eric Allman footnote:[Also kein Alman-Stil, der in Deutschland gepflegt wird ...] , bei dem die öffnende Klammer stets in einer eigenen Zeile steht:
int main()
{
if (…)
{
}
}
Eine weitere Variante ist der GNU-Stil, der im Umfeld des GNU-Projekts entstanden ist. Er ähnelt dem Allman-Stil, rückt jedoch die geschweiften Klammern und den Blockinhalt zusätzlich ein. Dadurch werden verschachtelte Strukturen stärker betont.
int main()
{
if (…)
{
…
}
}
Eine weitere anmutige Variante ist der Whitesmiths-Stil (benannt nach dem Whitesmiths-Compiler). Hier werden die Klammern eingerückt, und der Blockinhalt steht auf der gleichen Einrückungsebene wie die Klammern. Das betont die Hierarchie ähnlich wie GNU, aber mit einer anderen visuellen Trennung.
int main()
{
if (…)
{
…
}
}
Alle Varianten haben Anhänger und sind gleichermaßen korrekt. Ein paar Beispiele:
[cols="1,3", options="header"] |=== | Stil | Projekte
| K&R | Linux-Kernel, GNU Coreutils, Git, SQLite, BusyBox, GDB, OpenSSL, FFmpeg, PostgreSQL (C-Teile), Redis, Nginx, cURL (meist K&R-Varianten)
| Allman | FreeBSD, NetBSD, OpenBSD, Blender (C-Kernteile), Doom (id Software), Samba, PostgreSQL (ältere BSD-inspirierte Module), LLVM (einige C-Komponenten), Wine, Apache HTTP Server (teilweise Allman-inspiriert)
| GNU | GCC-Compiler, GIMP (C-Kernteile), GNU Emacs, GNU Make, GNU Binutils, Octave, GDB (ältere Versionen), GNU libc (glibc)
| Whitesmiths | Ältere Compiler-Tools, einige proprietäre Projekte (z. B. Whitesmiths-Compiler selbst), seltener in Open-Source, aber in manchen Legacy-Codes |===
Tabelle: Klammerstile in C-Projekten
In neueren C-Projekten (z. B. seit C11/C17) wird oft K&R oder Allman bevorzugt.
Tipp: Wichtig ist nicht, welcher Stil gewählt wird, sondern dass innerhalb eines Projekts ein einheitlicher Stil eingehalten wird. Ein Mischmasch aus verschiedenen Varianten erschwert das Lesen, weil die visuelle Struktur uneinheitlich wirkt.
Leerzeilen und Whitespace
Selbst bei korrekter Einrückung und konsistentem Klammerstil kann Code unübersichtlich wirken, wenn er ohne optische Gliederung notiert ist. Das Problem sind ›Codewände‹: viele Zeilen ohne visuelle Unterbrechung. Menschen lesen Programme nicht Zeichen für Zeichen, sondern erkennen Strukturen.
Leerzeilen helfen dabei, logische Abschnitte voneinander zu trennen. Typischerweise setzt man eine Leerzeile zwischen Funktionsdefinitionen oder zwischen größere Blöcke innerhalb einer Funktion.
Tipp: Verwende Whitespace, um Struktur sichtbar zu machen, aber missbrauche ihn nicht. Ein besonders unsinniges Beispiel ist es, das Semikolon und die geschweiften Klammern ganz nach rechts zu setzen, um den Eindruck zu erwecken, als ob C nur durch Einrückungen gesteuert würde und Anweisungen nicht mit einem Semikolon abgeschlossen werden müssten:
int main() { puts("Hello, world!") ; }
Moderne IDEs (z. B. Visual Studio Code, CLion, Code::Blocks, Dev-C++) und Tools wie clang-format (von LLVM), AStyle oder GNU indent wenden viele Stilregeln automatisch an:
- Einrückungen vereinheitlichen
- Klammerstile konsistent setzen (z. B. Konfigurationen für K&R, Allman oder GNU direkt unterstützen)
- Überflüssige Leerzeichen entfernen
- Leerzeilen sinnvoll einfügen
- Code nach projektspezifischen Styleguides formatieren (z. B. via
.clang-format-Dateien)
Damit bleibt der gesamte Code eines Teams einheitlich formatiert, unabhängig von persönlichen Vorlieben. Solche Tools können per Kommandozeile oder als IDE-Plugin integriert werden, um Auto-Formatting auf Save oder Commit zu ermöglichen.
