Werte und Typsystem

Die Hauptaufgabe der Programmierung ist die Manipulation von Werten. Um Werte manipulieren zu können, müssen in den Sprachen C und C++ sämtliche Werte einem eindeutigen Typ zugeordnet werden, der die strukturelle Interpretation der zugrunde liegenden Daten festlegt. Anhand dieses Typs kann der Compiler den Programmcode in die passenden Assembler-Befehle umwandeln. Dieses als Typisierung bekannte Konzept ist ein grundlegendes, mächtiges und weitreichendes Konzept der Sprachen C und C++.

Die Sprachen C und C++ spezifizieren eine kleine Anzahl an Basistypen sowie die Möglichkeit, Typen ineinander zu verschachteln, wodurch beliebige komplexe Typen erstellt werden können. Auf der Typen-Seite können sämtliche möglichen Typen nachgelesen werden.

Details

In Assembler wird mit Daten gearbeitet, in C und C++ dagegen mit Werten. Jeder Wert hat einen fest zugeordneten Typ, der die strukturelle Interpretation der zugrunde liegenden Daten festlegt. Somit ist eine genaue Kenntnis um die Speicherung der Daten nicht mehr notwendig, sondern es kann darauf vertraut werden, dass die Manipulationen von Werten vom Compiler aufgrund des Wissens um den Typ in die gewünschten Assembler-Befehle übersetzt wird.

In C und C++ treten drei zu unterscheidende Arten von Werten auf: Ein fester Wert im Programmcode (ein sogenanntes Literal), der Inhalt einer Variablen und der Rückgabewert eines Operators:

Fixed value
Variable containing a value
Operator returning a value
3.14159;
int x = 42;
x + x;

Feste Werte werden direkt in den Programmcode geschrieben und legen aufgrund der Syntax (wie sie geschrieben werden) implizit einen Typ fest. Diese Werte werden bereits während des Kompilierens fest in das Programm eincodiert und sind danach grundsätzlich nicht mehr ansprechbar, geschweige denn veränderbar. Die Schreibweise solcher Werte ist auf der Seite über feste Werte genauer beschrieben.

Variablen bezeichnen eine ansprechbare und veränderbare Stelle im Speicher oder in einem Prozessorregister. Um diese Stelle anzusprechen, wird als Platzhalter für den gesuchten Ort ein Symbol festgelegt, also ein benutzerdefinierter Name. Durch das Auftreten dieses Symbols im Programmtext wird automatisch der Wert der Variablen angesprochen. Damit der Compiler bei Auftreten eines Symbols weiss, wie die Daten an der anzusprechenden Stelle zu interpretieren sind, muss jedem Symbol ein Typ zugeordnet werden. Diese Zuordnung wird als Deklaration bezeichnet.

Operatoren erlauben es, Werte miteinander zu verknüpfen. Jeder Operator legt fest, was für Eingabewerte er verlangt und was für einen Rückgabewert er liefert. Beispielsweise verlangt der Additions-Operator zwei Eingabewerte und liefert einen Rückgabewert. Der Typ des Rückgabewertes ist für jeden Operator genau spezifiziert. Die detailierten Spezifikationen können bei den jeweiligen Operatoren nachgelesen werden. Die Rückgabewerte können in Ausdrücken verwendet werden, um mehrere Operationen sequentiell hintereinanderzuschalten, sie ineinander zu verschachteln, oder den Rückgabewert schlussendlich in einer Variablen zu speichern.

Es ist zu beachten, dass Funktionen ebenfalls einen Wert zurückgeben können. In C und C++ werden Funktionsaufrufe jedoch mit dem Funktionsaufruf-Operator abgearbeitet.

Bezeichnungen von Typisierungen

Die meisten modernen Programmiersprachen besitzen in irgend einer Form eine Typisierung. Eine Sprache, welche für Umwandlungen zwischen verschiedenen Typen explizite Anweisungen verlangt, wird als strongly typed (auch strong typing oder auf Deutsch stark typisiert) bezeichnet. Demgegenüber werden Typisierungen, welche automatische Umwandlungen sowie beispielsweise dynamische Auswertungen von Typen erlauben eher als weakly typed (auch weak typing oder auf Deutsch schwach typisiert) bezeichnet.

Des weiteren gibt es noch eine zweite Beschreibung der Typisierung. Programmiersprachen, welche zwingendermassen zu jedem Wert einen Typ verlangen, werden als strictly typed (auch strict typing oder auf Deutsch strikt oder streng typisiert) bezeichnet. Demgegenüber gibt es Programmiersprachen, welche den Typ eines Wertes (wie auch derjenige einer Variablen) automatisch festlegen oder gar dynamisch verändern, ohne dass jemals ein Typ angegeben werden muss. Solche Sprachen werden als loosely typed (auch loose typing oder auf Deutsch locker typisiert oder gar untypisiert) bezeichnet.

All diese englischen und deutschen Begriffe sind sehr verwirrend. Sie spielen jedoch auch nicht wirklich eine Rolle, solange nur in einer Sprache programmiert wird. Bei Portierungen zwischen verschieden typisierten Sprachen jedoch wird unweigerlich mit solchen Schlagwörter um sich geschlagen, weswegen der Autor hier versucht, auch C und C++ in diese Begriffe einzuordnen:

Die Programmiersprachen C und C++ sind grundsätzlich strikt typisiert, was bedeutet, dass jeder Wert einen fest deklarierten (statischen) Typ besitzt. Bei der Frage jedoch, ob C und C++ stark oder schwach typisiert seien, streiten sich verschiedene Quellen. Der Autor tendiert persönlich zur schwachen Variante, denn: Die Sprachen C und C++ erlauben, einen Wert (mehr oder weniger) beliebig umzuinterpretieren, wenn es denn gewünscht ist. Es ist beispielsweise möglich, einen float-Wert als int-Wert zu interpretieren (arithmetische Umwandlung), diesen Wert als Adresse zu casten und den Inhalt der Adresse als ein Objekt einer polymorphen Klasse anzusprechen. Dieses Beispiel macht wenig Sinn, allerdings gibt es Situationen, in denen weak-typing explizit angewendet wird, beispielsweise bei der Berechung von Array-Indizes. Da jedoch solche Umwandlungen fast immer explizit erfolgen müssen und moderne Compiler zudem normalerweise Warnungen oder gar Fehler ausgeben, wenn Typ-Umwandlungen keinen Sinn ergeben, können die Sprachen C und insbesondere C++ auch als stark typisiert bezeichnet werden. Durch explizite Angabe dessen, was tatsächlich erwünscht ist, können Warnungen dann auch entfernt werden.

Nächstes Kapitel: Variablen und Funktionen