Programmieren in C/C++: Vorwort

Wie ist dieses Buch entstanden Bearbeiten

Dieses Buch stammt aus der Vorlesung 'Programmieren in C' und dient dort als Skript für diese Vorlesung. Die Motivationen für die Veröffentlichung des Skripts in Wikibooks sind:

  • Bisher kein vernünftiges Lehrbuch für die Programmiersprache C gefunden. Viele Bücher basieren vorrangig auf praktischen Beispielen und vernachlässigen syntaktische Aspekte
  • Bereitstellung des Wissens für Personen außerhalb der Vorlesung
  • Interaktivität: Das heißt vorerst nicht, dass hier jeder mitschreiben soll. Vielmehr geht es mir um Rückmeldung bzgl. Verbesserungsvorschläge, Ergänzungsvorschläge,... über Diskussionsbeiträge

Für wen ist dieses Buch Bearbeiten

Die Zielgruppe für dieses Buch sind Personen mit Programmierkenntnissen. Es wird vorausgesetzt, dass der Leser weiß, was eine IF-Bedingung ist und wann eine FOR-Schleife anzuwenden ist. Schwerpunkt dieses Buches ist der Syntax der Sprache C/C++, die 'Interpretationen' daraus und die praktische Anwendung hiervon. Der Syntax von C/C++ kennt nur wenige Ausnahmeregeln, so dass quasi alles an allen Stellen erlaubt ist. Für unerfahrene Nutzer dieser Sprache führt dies oftmals zu Frust und der Aussagen wie 'Scheiß Compiler' / 'Scheiß Sprache'. In der Tat liegt das Problem vor der Tastatur. Moderne Programmiersprachen haben aus dem offenem Syntax von C/C++ gelernt und den Syntax entsprechend eingeschränkt. D.h. bspw. den Komma-Operator nur in FOR-Schleifen erlaubt und Zeiger durch Referenzen ersetzt. Damit wurden diverse Fehlerquellen unterbunden, aber gleichermaßen die Flexibilität der Sprache reduziert. Bei korrekter Anwendung der Syntaxen kann auch mit C/C++ saubere, sichere und vor allem schnelle Programme geschrieben werden.

Im Vergleich zu anderen Sprachen entspricht C (mit den Worten eines geschätzten Kollegen gesagt) einem 'senkrechtstartenden Düsenjäger'. Wenn der Pilot (resp. der Programmierer) das Werkzeug nicht beherrscht, führt es schnell zum Crash ('Scheiß Compiler'/'Scheiß Sprache'). Wenn er es beherrscht, kann er die Vorteile beider Welten nutzen.

Compiler ist dein Freund und Helfer Bearbeiten

Fehlermeldungen des Compilers werden nur ungern gelesen (derweil sie sich kryptisch anhören). Anstatt die Fehlermeldung zu lesen und zu verstehen, sehe ich oftmals folgenden Umgang mit Fehlermeldungen:

  • Nutzung der Lösungsvorschläge einer integrierten Entwicklungsumgebung
  • Vermeidung der Fehlermeldung durch Umstellung des Codes:
Mit Compilerfehler Umgehung der Fehlermeldung
int *foo(void) {
  int arr[10];
  ...
  return arr;
  //Error, aufgrund der Rückgabe
  //einer Adresse einer lokalen
  //Variablen
}
int *foo(void) {
  int arr[10];
  int *ptr;
  ...
  ptr=arr;
  //Adresse wird zuvor in eine
  //lokale Variable kopiert, so
  //dass der Compiler nicht prüfen
  //kann, woher die Adresse stammt
  return ptr;
}
  • Googlen nach Lösungsvorschlägen und Nutzung dieser (wobei die Autoren der Lösungsvorschläge den Fehler oftmals ebenfalls nicht verstanden haben und somit nur ein Workaround vorschlagen)
  • Ignorieren von Warnings (eigentlicher Fehler rächt sich dann zumeist später)
void foo(void) {	
  int *ptr;
  *ptr=4711;  //Warning, ptr is uninitialized
}

In der Tat ist die Fehlermeldung kryptisch. Der Grund für eine Fehlermeldung ist, dass der Source-Code von der Spezifikation abweicht und der Compiler entsprechend keinen Assemblercode generieren kann. Die Fehlermeldung beschreibt somit die Syntaxverletzung. Sie ist eine Hilfestellung an den Programmierer, was genau falsch ist. Als Programmierer sollte man sich bei Fehlermeldungen überlegen, was wollte man mit dem Ausdruck erreichen und was hat man in der Tat beschrieben. Also nicht einfach den Fehler korrigieren, sondern die Fehlermeldung als Anregung verstehen, den Code zu überdenken.

In den letzten Jahren sind die Compiler so intelligent geworden, dass diese bei vielen typischen Programmiererfehlern eine Warning ausgeben. Sie meckern, wenn bspw. eine Zuweisung in einer IF-Bedingung steht oder einer IF-Anweisung kein Block folgt (beides ist syntaktisch korrekt, sind aber gleichermaßen auch typische Zeichen für mögliche Fehler). Defaultmäßig sind einige diese Warnings deaktiviert. Da sie helfen können, mögliche Fehler zu vermeiden empfiehlt es sich, den Warning Level auf den höchsten Mode zu setzen (Compilerschalter: -Wall).

Programmieren lernt man nur durch Programmieren Bearbeiten

Lesen ist ein wichtiger Aspekt des Lernens, ausprobieren ein Weiterer. Beide ergänzen sich prima. In diesem Sinne sind im Buch viele Code-Beispiele vorhanden, ohne und zum Teil mit bewussten Fehlern.
Damit die notwendigen Include Anweisungen und ggf. Funktionsrümpfe den Beispielcode nicht unnötig aufblähen, wurde ein LUA Script entworfen (Danke an meinen Mitarbeiter), welches den im (verborgenen) im Buch enthaltenen Code in einen Compiler Explorer Link konvertiert. Über 'Öffnen im Compiler Explorer' können alle Beispiele ohne Abtippen direkt ausprobiert werden. Änderungen im Compilerexplorer sind lokale Änderungen und für den 'Rest' nicht sichtbar.
Über das LUA Script kann nicht nur Code vorgegebenen werden, sondern auch Compilerschalter und mehr gesetzt werden. Die Dokumentation zum Lua Code ist hier zu finden: Lua Doku. Der Lua Code selbst ist hier zu finden: Lua Code.

C/C++ Bearbeiten

Das Augenmerk des Buches liegt derzeit bei der Programmiersprache C. Viele grundlegende Konzepte sind in C und C++ identisch. Da C++ eine eigene Sprache ist, sind einige syntaktischen Abweichungen vorhanden. Im derzeitigen Stand des Buches bedeutet die Ergänzung C++ im Titel des Buches, diese syntaktischen Abweichungen zu beschreiben. Zukünftig ist geplant, die ergänzenden Konzepte wie Objektorientierung, Templates, Namensraum, ... zu ergänzen.

Compiler Bearbeiten

Die C-Spezifikation ist die Grundlage für alle Compilerhersteller. Insofern sind diese austauschbar. Die Spezifikation regelt das allgemeine Verhalten der Sprache, wie der Compiler dieses umsetzt, obliegt ihm. Über Compiler spezifische Schalter kann dem Compiler detailliertere Anweisungen für die Umsetzung gegeben werden (bei GCC über u.A. über __attribute__((attribute-list)), ab C++11 über [ [attribute-list] ]. An vielen Stellen gibt die C-Spezifikation ein undefiniertes Verhalten vor (z.B. bei der Rückgabe einer Adresse einer lokalen Variablen). Das Verhalten vom Compiler an diesen Stellen ist compilerabhängig. Einige fügen zusätzlichen Code ein (um z.B. zur Laufzeit einen Laufzeitfehler zu provozieren (Rückgabe der Adresse 0 im obigen Beispiel)), einige tätigen gar nichts. Ergänzend zur C-Spezifikation ergänzen einige Compiler die Spezifikation um zusätzliche Features. GCC beispielsweise ermöglicht es, in einer SWITCH-Anweisung ein CASE über einen Wertebereich zu beschreiben (Case 1 ... 3:).

Auch wenn die Sprache C sauber spezifiziert ist, wird man früher oder später compilerspezifische Eigenschaften nutzen und sich damit an einen Compiler binden. Im Falle dieses Buches ist es der GCC Compiler aus der GNU Compiler Collection.

Sonstiges Bearbeiten

Die C-Spezikation ist an einigen Stellen nur sehr schwer zu vermitteln. In diesem Sinne wird an einigen Stellen im Buch von C Spezifikation abgewichen. Dies soll der besseren Lesbarkeit/Verständnis dienen.