Zum Inhalt springen

„Include-Guard“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
Keine Bearbeitungszusammenfassung
WP:REV Das ist wohl keine Verbesserung
(Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt)
Zeile 1: Zeile 1:
Der '''Include Guard''' oder '''Include-Wächter''' ist eine Programmiertechnik, um in [[C (Programmiersprache)|C]] oder [[C++]] das Problem der mehrfachen Einbindung zu umgehen.
Der '''Include Guard''' (dt: ''Include Wächter'') ist eine Programmiertechnik, um in [[C (Programmiersprache)|C]] oder [[C++]] das Problem der doppelten Einbindung (engl.: ''double inclusion'') zu umgehen.


Dieses Problem tritt auf, wenn innerhalb eines [[Modul (Software)|Moduls]] mehrfach die gleiche [[Header-Datei]] eingebunden wird. Das geschieht in der Regel unbeabsichtigt, zum Beispiel wenn mehrere Header-Dateien die gleiche [[Programmbibliothek|Bibliothek]] benutzen.
Dieses Problem tritt auf, wenn innerhalb eines [[Modul (Software)|Moduls]] mehrfach die gleiche [[Header-Datei]] eingebunden wird. Das geschieht in der Regel unbeabsichtigt, zum Beispiel wenn mehrere Header-Dateien die gleiche [[Programmbibliothek|Bibliothek]] benutzen.
Zeile 32: Zeile 32:
</source>
</source>


Der Compiler liefert einen Fehler, weil eine Klasse oder Variable nochmals definiert wird.
Der Compiler liefert einen Fehler, weil eine Klasse oder Variable nochmals definiert wird (engl.: ''redefinition'').


== #ifndef Wrapper (oder Makro-Guard) ==
== Verhinderung der Mehrfacheinbindung mit Präprozessor-Variablen ==


Das Problem der Mehrfacheinbindung wird gelöst, indem eine eindeutige Präprozessor-Variable beim ersten Einbinden der Header-Datei definiert wird. War diese Variable bereits definiert, werden die Definitionen des Headers übersprungen:
Der ''#ifndef-Wrapper'' ist der traditionelle und C-konforme Ansatz. Er versucht das Problem zu lösen, indem er ein eindeutiges [[Makro#Makros_in_der_Programmierung|Makro]] beim ersten Einbinden der Header-Datei definiert. Ist dieses Makro bereits definiert, werden die Definitionen des Headers übersprungen:


<source lang="cpp">
<source lang="cpp">
Zeile 51: Zeile 51:
Im obigen Beispiel bewirkt das, dass beim erstmaligen Einbinden von ''A.h'' (aus ''program.cpp'') das Makro ''_A_H_'' noch nicht definiert ist und der [[C-Präprozessor|Präprozessor]] die Definitionen durchläuft. Beim zweiten Einbinden (aus ''B.h'') ist das Makro bereits definiert und der [[C-Präprozessor|Präprozessor]] überspringt den ''#ifndef .. #endif''-Block.
Im obigen Beispiel bewirkt das, dass beim erstmaligen Einbinden von ''A.h'' (aus ''program.cpp'') das Makro ''_A_H_'' noch nicht definiert ist und der [[C-Präprozessor|Präprozessor]] die Definitionen durchläuft. Beim zweiten Einbinden (aus ''B.h'') ist das Makro bereits definiert und der [[C-Präprozessor|Präprozessor]] überspringt den ''#ifndef .. #endif''-Block.


Problematisch ist ggf. eine potenzielle versehentliche Mehrfachverwendung der selben Präprozessor-Variablen<ref>[http://blogs.msdn.com/b/ericflee/archive/2008/04/17/pragma-once.aspx Eric Fleegal's WebLog] on [http://blogs.msdn.com/ MSDN Blogs]. Abgerufen am 19. August 2011.</ref>.
Das eigentliche Problem mit dieser Technik ist die sog. ''[[namespace pollution]]'': die definierten Makros liegen im globalen [[Namensraum]] und „verschmutzen“ diesen mit steigender Anzahl zusehends. Dem kann durch die Festlegung von Namenskonventionen zwar vorgebeugt werden, dies löst das Problem jedoch nicht<ref>[http://blogs.msdn.com/b/ericflee/archive/2008/04/17/pragma-once.aspx Eric Fleegal's WebLog] on [http://blogs.msdn.com/ MSDN Blogs]. Abgerufen am 19. August 2011.</ref>.


Der ''CPP'', der [[C-Präprozessor|Präprozessor]] des [[GNU Compiler Collection|GCC]], erkennt solche Konstrukte automatisch, merkt sich die entsprechenden Dateien und überspringt diese bei nochmaligem Einbinden<ref name="cpp_onceonlyheaders">[http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-Headers.html#Once_002dOnly-Headers Once-Only Headers] im [http://gcc.gnu.org/onlinedocs/cpp/index.html#Top GNU CPP Online Manual]. Abgerufen am 19. August 2011.</ref>.
Der ''CPP'', der [[C-Präprozessor|Präprozessor]] des [[GNU Compiler Collection|GCC]], erkennt solche Konstrukte automatisch, merkt sich die entsprechenden Dateien und überspringt diese bei nochmaligem Einbinden<ref name="cpp_onceonlyheaders">[http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-Headers.html#Once_002dOnly-Headers Once-Only Headers] im [http://gcc.gnu.org/onlinedocs/cpp/index.html#Top GNU CPP Online Manual]. Abgerufen am 19. August 2011.</ref>.


== #pragma Guard ==
== Verhinderung der Mehrfacheinbindung mit Hilfe von Spracherweiterungen ==


Sowohl der [[Microsoft Visual C++#Compiler|Microsoft C/C++ Compiler]]<ref>[http://msdn.microsoft.com/en-us/library/4141z1cx.aspx MSDN Visual Studio 2010 - once]</ref> als auch der [[GNU Compiler Collection|GCC]]<ref name="cpp_alternatives">[http://gcc.gnu.org/onlinedocs/cpp/Alternatives-to-Wrapper-_0023ifndef.html#Alternatives-to-Wrapper-_0023ifndef Alternatives to Wrapper #ifndef] im GNU CPP Online Manual. Abgerufen am 19. August 2011.</ref> unterstützen heute die Präprozessor-Direktive ''#pragma once''. Diese sorgt ebenfalls dafür, dass eine (Header-)Datei nur einmalig eingebunden wird, setzt jedoch auf höherer Ebene an (direkt am Präprozessor) und führt auch keine Makros in den globalen Namensraum ein.
Sowohl der [[Microsoft Visual C++#Compiler|Microsoft C/C++ Compiler]]<ref>[http://msdn.microsoft.com/en-us/library/4141z1cx.aspx MSDN Visual Studio 2010 - once]</ref> als auch der [[GNU Compiler Collection|GCC]]<ref name="cpp_alternatives">[http://gcc.gnu.org/onlinedocs/cpp/Alternatives-to-Wrapper-_0023ifndef.html#Alternatives-to-Wrapper-_0023ifndef Alternatives to Wrapper #ifndef] im GNU CPP Online Manual. Abgerufen am 19. August 2011.</ref> unterstützen heute die Präprozessor-Direktive ''#pragma once''. Diese sorgt ebenfalls dafür, dass eine (Header-)Datei nur einmalig eingebunden wird, setzt jedoch auf höherer Ebene an (direkt am Präprozessor) und führt auch keine Makros in den globalen Namensraum ein.
Zeile 69: Zeile 69:
</source>
</source>


Gerade bei portablem Code muss jedoch beachtet werden, dass dies eine Compiler-spezifische Erweiterung ist und nicht von jedem C++- oder C-Compiler unterstützt wird<ref name="cpp_alternatives" />.
Gerade bei portablem Code muss jedoch beachtet werden, dass dies eine Compiler-spezifische Erweiterung ist und nicht zwingend von jedem C/C++-Compiler unterstützt wird<ref name="cpp_alternatives" />.

== Siehe auch ==

* [http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Include_Guard_Macro Include Guard] im englischen Wikibooks.


== Einzelnachweise ==
== Einzelnachweise ==
<references/>
<references />


[[Kategorie:Programmiersprache C]]
[[Kategorie:Programmiersprache C]]
[[Kategorie:Programmiersprache C++]]
[[Kategorie:Programmiersprache C++]]


[[bg:Pragma once]]
[[bg:Include guard]]
[[en:Pragma once]]
[[en:Include guard]]
[[es:Pragma once]]
[[es:Include guard]]
[[ru:Pragma once]]
[[ru:Include guard]]
[[zh:Pragma once]]
[[zh:Include防範]]

Version vom 24. April 2012, 19:32 Uhr

Der Include Guard (dt: Include Wächter) ist eine Programmiertechnik, um in C oder C++ das Problem der doppelten Einbindung (engl.: double inclusion) zu umgehen.

Dieses Problem tritt auf, wenn innerhalb eines Moduls mehrfach die gleiche Header-Datei eingebunden wird. Das geschieht in der Regel unbeabsichtigt, zum Beispiel wenn mehrere Header-Dateien die gleiche Bibliothek benutzen.

Beispiel

// A.h
const int M = 123;

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


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

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


Im Hauptprogramm möchte man nun sowohl die Klasse A als auch B nutzen:

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

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

Der Compiler liefert einen Fehler, weil eine Klasse oder Variable nochmals definiert wird (engl.: redefinition).

#ifndef Wrapper (oder Makro-Guard)

Der #ifndef-Wrapper ist der traditionelle und C-konforme Ansatz. Er versucht das Problem zu lösen, indem er ein eindeutiges Makro beim ersten Einbinden der Header-Datei definiert. Ist dieses Makro bereits definiert, werden die Definitionen des Headers übersprungen:

// A.h
#ifndef _A_H_
#define _A_H_

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

#endif /* _A_H_ */

Im obigen Beispiel bewirkt das, 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 #ifndef .. #endif-Block.

Das eigentliche Problem mit dieser Technik ist die sog. namespace pollution: die definierten Makros liegen im globalen Namensraum und „verschmutzen“ diesen mit steigender Anzahl zusehends. Dem kann durch die Festlegung von Namenskonventionen zwar vorgebeugt werden, dies löst das Problem jedoch nicht[1].

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

#pragma Guard

Sowohl der Microsoft C/C++ Compiler[3] als auch der GCC[4] unterstützen heute die Präprozessor-Direktive #pragma once. Diese sorgt ebenfalls dafür, dass eine (Header-)Datei nur einmalig eingebunden wird, setzt jedoch auf höherer Ebene an (direkt am Präprozessor) und führt auch keine Makros in den globalen Namensraum ein.

Zur Verwendung genügt es innerhalb der Header-Datei die Anweisung #pragma once einzufügen:

// A.h
#pragma once

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

Gerade bei portablem Code muss jedoch beachtet werden, dass dies eine Compiler-spezifische Erweiterung ist und nicht zwingend von jedem C/C++-Compiler unterstützt wird[4].

Siehe auch

Einzelnachweise

  1. Eric Fleegal's WebLog on MSDN Blogs. Abgerufen am 19. August 2011.
  2. Once-Only Headers im GNU CPP Online Manual. Abgerufen am 19. August 2011.
  3. MSDN Visual Studio 2010 - once
  4. a b Alternatives to Wrapper #ifndef im GNU CPP Online Manual. Abgerufen am 19. August 2011.