Open Source im professionellen Einsatz
Linux-Magazin 02/2015
© CC-BY-SA Mark A. Wilson

© CC-BY-SA Mark A. Wilson

Modernes C++ in der Praxis – Folge 20

Statisch geprüft

Damit sein Code nicht als Bananensoftware beim Kunden reift, setzt der umsichtige C++-Lieferant auf die Funktion static_assert() und die Type-Traits-Bibliothek. Das dynamische Duo stellt Bedingungen an den Quellcode, die der Compiler zur Übersetzungszeit verifiziert.

501

Vorsicht ist die Mutter der Porzellankiste: Kontrolliert ein C++-Entwickler seinen Code bereits, noch während der Compiler ihn übersetzt, landen Fehler gar nicht erst in der Porzellankiste, also beim Kunden. Die Funktion »static_assert()« und die Type-Traits-Bibliothek helfen ihm dieses Ziel zu erreichen.

Kontrolle ist besser

Mit »static_assert()« lassen sich Bedingungen an den Quellcode stellen, die der Compiler beim Übersetzen testet. Damit schließt die Funktion ein Loch, das die Präprozessordirektive »#error« und das Makro »assert« hinterlassen. Denn »static_assert()« greift nach dem Präprozessorlauf ins Getriebe, aber noch bevor das System das Programm ausführt.

Die Syntax ist denkbar einfach: »static_assert(Ausdruck,Text)« . Während der Text, den die Software im Fehlerfall ausgibt, optional ist, muss C++ den Ausdruck zur Übersetzungszeit auswerten können, was keinen Einfluss auf die Laufzeit des Programms hat. Das unspektakuläre Listing 1 zeigt die Funktion in Aktion. Der Code lässt sich übersetzen, sofern ein »void*« -Zeiger auf der Plattform mindestens 8 Byte groß ist. Dem entgegen steht Listing 2, das nur eine Zeigergröße von 4 Bytes fordert.

Listing 2

static_assert() in verschiedenen Bereichen

01 static_assert(sizeof(void*) == 4, "32-bit addressing required");
02
03 namespace namespaceScope{
04 static_assert(sizeof(void*) == 4, "32-bit addressing required");
05 }
06
07 void functionScope(){
08   static_assert(sizeof(void*) == 4, "32-bit addressing required");
09 }
10
11 class ClassScope{
12   static_assert(sizeof(void*) == 4, "32-bit addressing required");
13 };
14
15 int main(){
16   {
17     static_assert(sizeof(void*) == 4, "32-bit addressing required");
18   }
19 }

Listing 1

Eine einfache Zusicherung

01 int main(){
02   static_assert(sizeof(void*) >= 8, "64-bit addressing is required for this program");
03 }

Wie Abbildung 1 zeigt, trifft diese zweite Forderung auf die Testmaschine nicht zu, die nach einer 64-Bit-Adressierung verlangt. Daneben zeigt die Abbildung vor allem zwei Dinge: Erstens dass »static_assert()« jeden Aufruf evaluiert, und zwar unabhängig davon, ob der Code tatsächlich zum Einsatz kommt. Dies gilt für den Aufruf im globalen Bereich (Zeile 3), im Funktionsbereich (Zeile 8), im Klassenbereich (Zeile 12) und im Blockbereich (Zeile 17). Zweitens zeigt es, dass die Fehlermeldung den Text des »static_assert()« -Aufrufs direkt verwendet: »error: static assertion 12: 32-bit adressing required« .

Abbildung 1: Die Funktion static_assert() deckt verschiedene Bereiche ab.

Seine volle Wirkung entfaltet »static_assert()« aber erst, wenn der Entwickler den Aufruf mit der Type-Traits-Bibliothek kombiniert.

Ein perfektes Paar

Da der Compiler die Funktionen der Type-Traits-Bibliothek beim Übersetzen ausführt, erweist diese sich als idealer Kandidat für die »static_assert()« -Funktion. Die braucht ja Ausdrücke, die der Compiler zur Übersetzungszeit evaluiert. Die Type-Traits-Bibliothek hat dabei einiges auf dem Kasten, allem voran kann sie Typen analysieren, vergleichen und sogar transformieren.

Vor der Kür aber kommt die Pflicht. Ziel des Artikels ist es, generische, typsichere Funktionen zu implementieren, die den größten gemeinsamen Teiler (GGT, [1]) zweier ganzer Zahlen berechnen. Die Funktionen sollen auf dem Algorithmus von Euklid ([2], Abbildung 2) basieren.

© © CC-BY-SA Mark A. WilsonAbbildung 2: Der Mathematiker Euklid hat ein paar schöne Algorithmen erfunden.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • C++

    Implizite Typkonvertierungen sind eine der Ursachen für undefiniertes Verhalten in C- und C++-Programmen. In Kurzform bedeutet dies, dass solche Programme alles Mögliche tun dürfen und unvorhersehbar reagieren. C++-Routinier Rainer Grimm zeigt, wie C++-Entwickler diese Falle umgehen.

  • C++11

    C++11 kennt zwei neue Literale: Raw-String- und benutzerdefinierte Literale. Während Raw-String-Literale den Interpreter zum Beispiel davon abbringen, Backslashes in Zeichenketten zu interpretieren, schützen benutzerdefinierte Literale dereinst womöglich Nasa-Sonden vor dem Verglühen.

  • C++11

    Indem er das Zauberwort "constexpr" anwendet, erreicht der Programmierer, dass C++11 seine Ausdrücke bereits beim Kompilieren auswertet. Folgt er dabei den vorgefertigen Beschwörungsritualen, generieren solche konstanten Ausdrücke Performancegewinne.

  • Erfrischend neu

    An der Sprache C++ ändert sich selten etwas. Doch nun steht mit dem C++0x ein neuer Standard vor der Tür, von dem Neulinge wie Könner profitieren sollen. Mit Move-Semantik, Lambda-Funktionen und Aggregatzuweisungen bringt er viele Modernisierungen in die Programmiersprache.

  • C++11

    Klein, aber oho: Platziert ein Entwickler drei Punkte ("…") geschickt an der richtigen Stelle im C++-Code, entpacken die so genannten Variadic Templates ihre Argumente an Ort und Stelle.

comments powered by Disqus

Ausgabe 10/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.