Include-Guard

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

Der Include-Guard oder Include-Wächter ist eine Programmiertechnik, um in C und C++ das Problem der mehrfachen Einbindung zu lösen.

Dieses Problem tritt auf, wenn innerhalb einer Übersetzungseinheit mehrmals die gleiche Header-Datei eingebunden wird. Das geschieht in der Regel unbeabsichtigt, z. B. wenn mehrere Module die gleiche Bibliothek benutzen.

Beispiel einer Mehrfacheinbindung

[Bearbeiten | Quelltext bearbeiten]

Gegeben seien die folgenden beiden Header-Dateien A.h und B.h, die u. a. jeweils eine Klasse definieren:

// A.h
const int M = 123;

class A
{ /* ... */ };
// B.h
#include "A.h"

class B : public A
{ /* ... */ };

Im Hauptprogramm sollen nun sowohl die Klasse A als auch B genutzt werden:

// program.cpp
#include "A.h"
#include "B.h"

int main() { /* ... */ }

Das Programm lässt sich nicht fehlerfrei kompilieren, weil die Klasse A doppelt definiert wird: Die erste Definition erfolgt beim Einbinden der Header-Datei A.h in Zeile 2. Die zweite Definition erfolgt, weil die Header-Datei B.h, die in Zeile 3 eingebunden wird, selbst wiederum A.h einbindet. Die Klasse (und ggf. weitere Variablen) aus dieser Datei wurden bereits zuvor definiert, was zu einem Fehler der Kompilierung führt.

Lösung mit Präprozessor-Makros (#ifndef)

[Bearbeiten | Quelltext bearbeiten]

Der #ifndef-Wrapper ist der traditionelle und C-konforme Ansatz. Das Problem der Mehrfacheinbindung wird durch Definition eines eindeutigen Präprozessor-Makros beim ersten Einbinden der Header-Datei gelöst. War das Makro bereits definiert, werden die nachfolgenden Definitionen des Headers übersprungen:

// A.h
#ifndef A_H
#define A_H

class A
{ /* ... */ };

#endif /* A_H */

Die obenstehenden Präprozessor-Befehle bewirken, dass beim erstmaligen Einbinden von A.h (aus program.cpp) das Makro A_H noch nicht definiert ist und der Präprozessor die Definitionen durchläuft. Beim zweiten Einbinden (aus B.h) ist das Makro bereits definiert und der Präprozessor überspringt den Block #ifndef … #endif.

Da Makros im globalen Namensraum existieren, kann es hier zu Problemen kommen, wenn versucht wird, den gleichen Namen an anderer Stelle zu verwenden (sog. namespace pollution). Dem kann durch die Festlegung von Namenskonventionen zwar vorgebeugt werden, es löst das Problem dennoch nicht.[1] Für compiler-eigene Definitionen und Definitionen in den Standard-Bibliotheken sind Bezeichner mit führendem Unterstrich (_) reserviert. Ein führender Unterstrich darf nach den aktuellen C- und C++-Standards daher nicht im Applikationscode verwendet werden.[2][3]

Der CPP, der Präprozessor der GCC, erkennt solche Konstrukte automatisch, merkt sich die entsprechenden Dateien und überspringt diese bei nochmaligem Einbinden.[4]

Lösung über Spracherweiterungen (#pragma once)

[Bearbeiten | Quelltext bearbeiten]

Die meisten gebräuchlichen C- und C++-Compiler unterstützen heute die Spracherweiterung #pragma once. Diese sorgt ebenfalls dafür, dass eine (Header-)Datei nur einmal eingebunden wird, setzt jedoch auf höherer Ebene, direkt am Präprozessor, an und führt auch keine Makros in den globalen Namensraum ein.

Zur Verwendung genügt es, innerhalb der Header-Datei die Präprozessordirektive #pragma once einzufügen:

// A.h
#pragma once

class A
{ /* ... */ };

Diese Spracherweiterung wird von den folgenden C++-Implementierungen unterstützt:

Einzelnachweise

[Bearbeiten | Quelltext bearbeiten]
  1. Eric Fleegal’s WebLog@1@2Vorlage:Toter Link/blogs.msdn.com (Seite nicht mehr abrufbar, festgestellt im April 2018. Suche in Webarchiven)  Info: Der Link wurde automatisch als defekt markiert. Bitte prüfe den Link gemäß Anleitung und entferne dann diesen Hinweis. on MSDN Blogs; abgerufen am 19. August 2011.
  2. C++ standard (ISO/IEC 14882); C++ working draft N3242 (PDF; 10 MB), Abschnitt 17.6.4.3.2
  3. C standard (ISO/IEC 9899); Committee Draft N1124 (PDF; 3,3 MB), Abschnitte 6.10.8 und 7.1.3/1.
  4. Once-Only Headers im GNU CPP Online Manual. Abgerufen am 19. August 2011.
  5. GCC 3.4 Release Series − Changes, New Features, and Fixes. Abgerufen am 16. Mai 2014.
  6. clang: Pragma.cpp Source File (Memento des Originals vom 4. April 2014 im Internet Archive)  Info: Der Archivlink wurde automatisch eingesetzt und noch nicht geprüft. Bitte prüfe Original- und Archivlink gemäß Anleitung und entferne dann diesen Hinweis.@1@2Vorlage:Webachiv/IABot/clang.llvm.org. Abgerufen am 16. Mai 2014.
  7. MS Developer Network − once (C/C++). Abgerufen am 16. Mai 2014.
  8. Comeau C++ 4.0 (Memento des Originals vom 11. Dezember 2013 im Internet Archive)  Info: Der Archivlink wurde automatisch eingesetzt und noch nicht geprüft. Bitte prüfe Original- und Archivlink gemäß Anleitung und entferne dann diesen Hinweis.@1@2Vorlage:Webachiv/IABot/www.comeaucomputing.comPre-Release − User-Documentation: Pragmas (Memento des Originals vom 11. Dezember 2013 im Internet Archive)  Info: Der Archivlink wurde automatisch eingesetzt und noch nicht geprüft. Bitte prüfe Original- und Archivlink gemäß Anleitung und entferne dann diesen Hinweis.@1@2Vorlage:Webachiv/IABot/www.comeaucomputing.com. Abgerufen am 16. Mai 2014.
  9. #pragma once - RAD Studio XE3. Abgerufen am 16. Mai 2014.
  10. Pragmas #pragma once. Abgerufen am 16. Mai 2014.