Ok, im letzten Teil habe ich kurz ein paar Bücher, Editoren und Compiler bzw Entwicklungsumgebungen für die C++ Programmierung aufgezählt. Am Ende habe ich noch das erste kleine Programm in den Editor getippt und übersetzt. Genau an der Stelle will ich heute wieder ansetzen und anhand des Hello World Programms erläutern, was der Compiler / Linker beim Übersetzen so macht und was die einzelnen Teile des simplen Programms zu bedeuten haben.

Ja, das klingt noch nicht spannend … und soviel kann ich schon mal sagen. Bis zur Programmierung eigener VST-Plugins wird es noch etwas dauern. Die C++ Grundlagen werden so einige Artikel umfassen und für den ein oder anderen die ganze Zeit nicht allzu spannend sein. Für mich sind sie das schon und darum kann ich es kaum abwarten anzufangen…

Hello, C++-world!

// helloworld.cpp
// This program outputs the message "Hello, C++-world!" 
// on the screen
#include <iostream>

using namespace std;
// C++ programs starts by executing the function main
int main() {    
    // output "Hello, C++-world!"
    cout << "Hello, C++-world!" << endl;    
    return 0;
}

Den Quellode speichern wir unter dem Namen helloword.cpp in unseren C++-Ordner. Um das Programm zu übersetzen rufen wir folgenden Befehl auf:

$> c++ helloworld.cpp -o helloworld

Dies sind nun die Anweisungen an unseren Computer. Wir sollten ganz kurz schauen, was jede Zeile hier macht…

// helloworld.cpp
// This program outputs the message "Hello, C++-world!" 
// on the screen

Hierbei handelt es sich um Kommentare. Ein Kommentar wird vom Compiler komplett ignoriert. Ich kann also im Grunde jeden Blödsinn in einen Kommentar schreiben. Das würde aber keinen Sinn machen, denn Kommentare sind äußerst wichtig. Sie helfen dem Programmierer Programme zu verstehen, entweder die eigenen, wenn man nach Monaten mal wieder auf den Quellcode schaut, oder sie helfen anderen Programmierern zu verstehen, was der Urheber des Codes sich dabei gedacht hat.

Es gibt zwei Arten von Kommentaren in C++:

// Einzeilige Kommentare:
// Alles was hinter zwei Schrägstrichen steht, wird für
// den Rest der jeweiligen Zeile vom Compiler ignoriert

/*
Mehrzeilige Kommentare:
Alles was hier zwischen steht wird vom Compiler
ignoriert.
*/

Ich habe mir angewöhnt Kommentare immer in englischer Sprache zu verfassen. Diesen Stil halte ich persönlich konsequent ein. Für die meisten größeren Projekte gibt es aber immer Styleguides, die vorgeben wie gewisse Dinge im Quellcode zu handhaben sind. Es ist vielleicht mal ganz interessant solch einen Styleguide zu überfliegen…

#include <iostream>

… ist eine #include Direktive. Hiermit geben wir dem Computer die Anweisung alles aus der Bibliothek iostream für unser Programm verfügbar zu machen. Diese Bibliothek enthält Funktionen zur Ein- und Ausgabe von Text. Mehr müssen wir an dieser Stell noch gar nicht wissen. Später werden wir auf #include Direktiven noch näher eingehen.

Woher weiß der Computer, an welcher Stelle er anfangen soll das Programm auszuführen? Er sucht nach der Funktion mit dem Namen main und führt als erstes alle Anweisungen aus, die er darin findet. In unserem Programm sieht die main Funktion so aus:

int main() {    
    // output "Hello, C++-world!"
    cout << "Hello, C++-world!" << endl;    
    return 0;
}

Jedes C++ Programm MUSS diese Funktion enthalten, damit das Programm weiß, wo es mit der Ausführung beginnen soll. Eine Funktion ist im Grunde nur eine Reihe von Anweisungen für den Computer, die er der Reihe nach abarbeiten soll. Eine Funktion hat vier Teile:

  • Einen Rückgabewert, in diesem Fall int (integer), der festlegt, welche Art von Ergebnis die Funktion nach dem Abarbeiten zurückgeben soll. Das Wort int ist ein Schlüsselwort in C++, d.h. man kann es nicht als Namen für eigene Datentypen verwenden.
  • Einen Namen, in diesem Fall main
  • Eine Parameterliste in Klammern eingeschlossen, in diesem Fall (), also ist die Parameterliste hier leer.
  • Einen Funktionskörper in geschweiften Klammern eingeschlossen, {}, welcher die einzelnen Aktionen enthält, die die Funktion ausführen soll.

Dementsprechend wäre das minimalistischste C++ Programm:

int main() { }

Das wäre kein sinnvolles Programm, weil es einfach nichts tut. Die main Funktion in unserem Programm enthält zwei Anweisungen:

cout << "Hello, C++-world!" << endl;    
return 0;

Zuerst schreibt sie Hello, C++-world! auf den Bildschirm und dann gibt sie den Wert 0 (null) zurück an denjenigen, der die Funktion aufgerufen hat. Da main() vom System aufgerufen wurde, wird dieser Rückgabewert im Grunde nicht benötigt.

Moment, es gibt noch eine Zeile, die wir im letzten Artikel gar nicht im Hello World Programm hatten, nämlich…

using namespace std;

Was hat es damit auf sich? Hier wird dem Compiler mitgeteilt in einem bestimmten Namensraum zu agieren. Namensräume sind ein Thema für spätere Artikel. Nur so viel: Durch die Angabe den Namensraum std zu benutzen, können wir uns bei allen Befehlen aus diesem Namensraum (hier: cout und endl), die explizite Angabe des Namensraums bei jeder Verwendung der Befehle sparen (z.B. std::cout). Auch wenn das jetzt etwas verwirrend klingt, es macht im Moment das Abtippen der Programme etwas einfacher. 😉

Kompilierung

C++ ist eine kompilierte Sprache. D.h. wir müssen unseren Quellcode erst in etwas Umwandeln, dass der Rechner auch lesen kann. Diese Übersetzung macht der Compiler. Was wir lesen und schreiben ist ein Quellcode oder Programmtext und was der Rechner ausführt ist eine ausführbare Datei, Objektcode oder Maschinencode. Normalerweise haben C++ Quellcode Dateien die Endung .cpp (manchmal auch .cc oder .C) oder .h (wenn es sich um sogenannte Header handelt … dazu an anderer Stelle mehr).

Der Objektcode hat meistens die Endung .exe (Windows) oder .out bzw. .0 (Unix). Der Compiler liest den Quellcode und versucht sich daraus einen Reim zu machen. Er schaut, ob das Programm syntaktisch korrekt ist und ob es etwas offensichtlich Falsches im Code gibt. Wir werden feststellen, das der Compiler recht kleinlich ist, was die Syntax angeht. Wenn auch nur das kleinste Detail ausgelassen wird, z.B. ein Semikolon vergessen, eine geschweifte Klammer weggelassen oder die #include Anweisung nicht korrekt ist, wirft er einen Fehler aus.

Während des Programmierens kann einem der Compiler schon ganz schön auf die Nerven gehen. Er regt sich halt über die kleinsten Kleinigkeiten auf. Nichtdestotrotz, der Compiler hat eigentlich immer Recht! Falls er einen Fehler meldet und den Code nicht kompilieren will, dann ist auch etwas fehlerhaft im Programmtext. Aber manchmal hilft er auch beim Finder des Fehlers…

Falls man ein Semikolon vergisst, merkt der Compiler das!

Linking

Ein C++ Programm besteht normalerweise aus mehreren einzelnen Teilen, meistens sogar von verschiedenen Programmieren verfasst. Z.B. besteht unser Hello World Beispiel aus dem Teil, den wir geschrieben haben und Teilen aus der C++ Standard Library (hier: iostream). Diese einzelnen Teile müssen kompiliert werden und die daraus entstandenen Objektcode-Dateien müssen verknüpft (linking) werden, um ein ausführbares Programm zu bilden. Das Programm, dass diese Verknüpfung übernimmt, heißt (kaum zu glauben) Linker.

Wichtig ist noch zu wissen, dass Objektcodes und ausführbare Dateien nicht portabel für verschiedene Betriebssysteme sind. Wenn ich z.B. einen Quellcode auf einem Windows Rechner kompiliere, läuft dieses Programm nicht unter Linux. Dafür müsste ich dann den Quellcode erneut auf dem gewünschten System kompilieren.

Soviel erstmal für den Anfang und für das grobe Verständnis des Hello World Einführungsbeispiels. Im nächsten Teil geht es dann mit Variablen und grundlegenden Datentypen weiter…