C++-Programmierung: Grundlagen
Eine aktuelle Seite zum gleichen Thema ist unter C++-Programmierung/ Einführung zum Buch/ Es war einmal… und C++-Programmierung/ Einführung zum Buch/ Compiler verfügbar.
C++ wurde ab 1979 von Bjarne Stroustrup entwickelt, während er bei Bell Labs arbeitete. Sein Ziel war die Entwicklung einer Programmiersprache mit den Fähigkeiten von C, aber freier Wahl der Programmier-Paradigmen. C++ wurde in den 90er Jahren immer populärer und 1998 von der ISO standardisiert (ISO-14882).
Ein Problem von C++, das aus der relativen Paradigmenfreiheit folgt, ist, dass kein Compiler vollständig standardkonform ist. Viele Compiler haben ihre Wurzeln in der Zeit vor der Standardisierung und erfüllen den Standard daher recht unterschiedlich.
Einführung
BearbeitenDie Anweisungen eines jeden C++-Programms werden in Textdateien aufgeschrieben, deren Namen in der Regel die Endung .cpp
oder .cc
haben. Diese Dateien heißen Quelltext (source code). Dieser ist für Menschen lesbar und (sofern man C++ beherrscht, hoffentlich auch) verständlich. Der Prozessor des Computers kann damit aber wenig anfangen, er versteht ausschließlich Maschinensprache, vereinfacht gesagt eine Folge von Nullen und Einsen. Ein C++-Compiler übersetzt den Quelltext in Maschinensprache und erzeugt so eine (auf dem jeweiligen Prozessortyp) direkt ausführbare Datei (executable).
Damit grenzt sich C++ als compilierende Sprache von den interpretierten Sprachen ab, bei denen ein Maschinenprogramm, der so genannte Interpreter, direkt auf dem Prozessor läuft und Anweisungen aus dem Quelltext Schritt für Schritt ausführt.
Um ein C++-Programm in eine ausführbare Datei zu übersetzen, sind mehrere Schritte notwendig, die früher meist einzeln aufgerufen werden mussten, inzwischen aber bei den meisten Compilern intern ausgeführt oder gar übersprungen werden:
- Präprozessor: wertet Präprozessordirektiven (z.B.
#include
oder#define
) aus - C++-Compiler: erzeugt aus dem C++-Code C-Code (für jede Quelltextdatei)
- C-Compiler: übersetzt jede C-Quelltextdatei einzeln in eine eigene Assemblerdatei
- Assembler: erzeugt aus den Assembleranweisungen jeweils eine Objektdatei
- Linker: führt mehrere Objektdateien zu einer einzelnen ausführbaren Datei zusammen
Aktuelle Compilerimplementierungen besitzen einen internen Präprozessor und erzeugen direkt aus dem C++-Code Objektdateien. Oft ist auch der Linker integriert. Dennoch ist es auch heute noch bei vielen Compilern möglich, nur einzelne Schritte auszuführen, z.B. sich den erzeugten Assemblercode ausgeben zu lassen.
Die Bezeichnung „Objektdatei“ hat nichts mit objektorientierter Programmierung zu tun, es geht nicht um Instanzen irgendwelcher Klassen. Eine Objektdatei (object file) enthält Maschinensprache zusammen mit Informationen darüber, wo welcher Teil des Codes beginnt (Positionen der Funktionen und Variablen usw.). So kann der Linker Objektdateien - die von verschiedenen Compilern aus Quelltext verschiedener Programmiersprachen erzeugt sein können - zu einem Programm binden. Unabhängig von der Herkunft der entsprechenden Objektdateien können sich die Funktionen gegenseitig aufrufen und Variablen gemeinsam nutzen. Je nach Computerarchitektur und Betriebssystem existieren verschiedene Objektdateiformate, die im Allgemeinen nicht kombinierbar sind. Gängige Endungen sind .o
und .obj
.
Die Aufgabe eines Linkers ist komplexer als etwa das bloße Zusammenkopieren verschiedener Objektdateien, vielmehr muss er die tatsächlichen Positionen der Funktionen und Variablen in der ausführbaren Datei festlegen und gegenseitig bekannt machen und Metainformationen für den Programmlader des Betriebssystems speichern.
Der C++-Standard kümmert sich übrigens nicht um die meisten Details dieses Abschnitts, für ihn existiert nicht einmal das Konzept der Dateien. Insofern gibt dieser Abschnitt lediglich einen Überblick über konkrete Implementierungen.