Namensräume
Varianten
Aktionen

Einbeziehung von Quelldateien

Von cppreference.com
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Bindet andere Quelldateien in die aktuelle Quelldatei unmittelbar nach der Direktive ein.

Inhalt

[bearbeiten] Syntax

#include < h-char-sequence > new-line (1)
#include " q-char-sequence " new-line (2)
#include pp-tokens new-line (3)
__has_include ( " q-char-sequence " )
__has_include ( < h-char-sequence > )
(4) (seit C++17)
__has_include ( string-literal )
__has_include ( < h-pp-tokens > )
(5) (seit C++17)
1) Sucht nach einem Header, der eindeutig durch h-char-sequence identifiziert wird, und ersetzt die Direktive durch den gesamten Inhalt des Headers.
2) Sucht nach einer Quelldatei, die durch q-char-sequence identifiziert wird, und ersetzt die Direktive durch den gesamten Inhalt der Quelldatei. Kann auf (1) zurückfallen und q-char-sequence als Header-Identifikator behandeln.
3) Wenn weder (1) noch (2) zutreffen, wird pp-tokens einer Makroersetzung unterzogen. Die Direktive nach der Ersetzung wird erneut versucht, mit (1) oder (2) abzugleichen.
4) Prüft, ob ein Header oder eine Quelldatei zur Einbindung verfügbar ist.
5) Wenn (4) nicht zutrifft, wird h-pp-tokens einer Makroersetzung unterzogen. Die Direktive wird nach der Ersetzung erneut versucht, mit (4) übereinzustimmen.
new-line - Das Zeilenumbruchzeichen
h-char-sequence - Eine Sequenz von einem oder mehreren h-chars, wobei das Auftreten der folgenden Elemente bedingt unterstützt wird und Implementierungs-definierte Semantik hat:
  • das Zeichen '
  • das Zeichen "
  • das Zeichen \
  • die Zeichensequenz //
  • die Zeichensequenz /*
h-char - Jedes Mitglied des Quellzeichensatzes(bis C++23)Übersetzungszeichensatzes(seit C++23) außer Zeilenumbruch und >
q-char-sequence - Eine Sequenz von einem oder mehreren q-chars, wobei das Auftreten der folgenden Elemente bedingt unterstützt wird und Implementierungs-definierte Semantik hat:
  • das Zeichen '
  • das Zeichen \
  • die Zeichensequenz //
  • die Zeichensequenz /*
q-char - Jedes Mitglied des Quellzeichensatzes(bis C++23)Übersetzungszeichensatzes(seit C++23) außer Zeilenumbruch und "
pp-tokens - Eine Sequenz von einem oder mehreren Präprozessor-Tokens
string-literal - Ein String-Literal
h-pp-tokens - Eine Sequenz von einem oder mehreren Präprozessor-Tokens außer >

[bearbeiten] Erklärung

1) Sucht in einer Sequenz von Implementierungs-definierten Orten nach einem Header, der eindeutig durch h-char-sequence identifiziert wird, und bewirkt die Ersetzung dieser Direktive durch den gesamten Inhalt des Headers. Wie die Orte spezifiziert oder der Header identifiziert wird, ist Implementierungs-definiert.
2) Bewirkt die Ersetzung dieser Direktive durch den gesamten Inhalt der durch q-char-sequence identifizierten Quelldatei. Die benannte Quelldatei wird auf eine Implementierungs-definierte Weise gesucht. Wenn diese Suche nicht unterstützt wird oder fehlschlägt, wird die Direktive neu verarbeitet, als ob sie die Syntax (1) mit der identischen enthaltenen Sequenz (einschließlich > Zeichen, falls vorhanden) aus der ursprünglichen Direktive gelesen hätte.
3) Die Präprozessor-Tokens nach include in der Direktive werden wie in normalem Text verarbeitet (d.h. jeder als Makroname definierte Bezeichner wird durch seine Ersetzungsliste von Präprozessor-Tokens ersetzt). Wenn die Direktive nach allen Ersetzungen eine der beiden vorherigen Formen nicht übereinstimmt, ist das Verhalten undefiniert. Die Methode, mit der eine Sequenz von Präprozessor-Tokens zwischen einem Präprozessor-Token-Paar < und > oder einem Paar von " Zeichen in ein einzelnes Header-Name-Präprozessor-Token kombiniert wird, ist Implementierungs-definiert.
4) Die durch h-char-sequence oder q-char-sequence identifizierte Header- oder Quelldatei wird gesucht, als ob diese Präprozessor-Token-Sequenz die pp-tokens in der Syntax (3) wären, außer dass keine weitere Makroerweiterung durchgeführt wird. Wenn eine solche Direktive die syntaktischen Anforderungen einer #include Direktive nicht erfüllen würde, ist das Programm fehlerhaft. Der Ausdruck __has_include ergibt 1, wenn die Suche nach der Quelldatei erfolgreich ist, und 0, wenn die Suche fehlschlägt.
5) Diese Form wird nur berücksichtigt, wenn die Syntax (4) nicht zutrifft; in diesem Fall werden die Präprozessor-Tokens wie in normalem Text verarbeitet.

Wenn der durch den header-name (d.h. < h-char-sequence > oder " q-char-sequence ") identifizierte Header ein importierbarer Header ist, ist es Implementierungs-definiert, ob die #include Präprozessor-Direktive stattdessen durch eine import-Direktive der Form ersetzt wird

import header-name ; new-line

(seit C++20)

__has_include kann im Ausdruck von #if und #elif erweitert werden. Es wird von #ifdef, #ifndef, #elifdef, #elifndef(seit C++23) und defined als definiertes Makro behandelt, kann aber nirgendwo sonst verwendet werden.

[bearbeiten] Anmerkungen

Typische Implementierungen suchen nur in Standard-Include-Verzeichnissen für die Syntax (1). Die Standard-C++-Bibliothek und die Standard-C-Bibliothek sind implizit in diesen Standard-Include-Verzeichnissen enthalten. Die Standard-Include-Verzeichnisse können normalerweise vom Benutzer über Compiler-Optionen gesteuert werden.

Die Absicht der Syntax (2) ist es, nach Dateien zu suchen, die nicht von der Implementierung gesteuert werden. Typische Implementierungen suchen zuerst im Verzeichnis, in dem sich die aktuelle Datei befindet, und greifen dann auf (1) zurück.

Wenn eine Datei eingebunden wird, wird sie durch die Übersetzungsphasen 1-4 verarbeitet, was rekursiv die Erweiterung verschachtelter #include Direktiven bis zu einer Implementierungs-definierten Verschachtelungsgrenze beinhalten kann. Um wiederholte Einbindungen derselben Datei und endlose Rekursion zu vermeiden, wenn eine Datei sich selbst einbindet, vielleicht transitiv, werden *Header Guards* üblicherweise verwendet: der gesamte Header wird umschlossen in

#ifndef FOO_H_INCLUDED /* any name uniquely mapped to file name */
#define FOO_H_INCLUDED
// contents of the file are here
#endif

Viele Compiler implementieren auch das nicht-standardmäßige pragma #pragma once mit ähnlichen Effekten: es deaktiviert die Verarbeitung einer Datei, wenn dieselbe Datei (wobei die Dateiidentität OS-spezifisch bestimmt wird) bereits eingebunden wurde.

Eine Zeichensequenz, die wie eine Escape-Sequenz in q-char-sequence oder h-char-sequence aussieht, kann je nach Implementierung zu einem Fehler führen, als das Zeichen interpretiert werden, das der Escape-Sequenz entspricht, oder eine völlig andere Bedeutung haben.

Ein Ergebnis von __has_include von 1 bedeutet nur, dass eine Header- oder Quelldatei mit dem angegebenen Namen existiert. Es bedeutet nicht, dass die Header- oder Quelldatei beim Einbinden keinen Fehler verursacht oder etwas Nützliches enthält. Zum Beispiel kann auf einer C++-Implementierung, die sowohl C++14- als auch C++17-Modi unterstützt (und __has_include in ihrem C++14-Modus als konforme Erweiterung bereitstellt), __has_include(<optional>) im C++14-Modus 1 sein, aber tatsächlich kann #include <optional> einen Fehler verursachen.

[bearbeiten] Beispiel

#if __has_include(<optional>)
    #include <optional>
    #define has_optional 1
    template<class T>
    using optional_t = std::optional<T>;
#elif __has_include(<experimental/optional>)
    #include <experimental/optional>
    #define has_optional -1
    template<class T>
    using optional_t = std::experimental::optional<T>;
#else
    #define has_optional 0
    template<class V>
    class optional_t
    {
        V v{};
        bool has{};
 
    public:
        optional_t() = default;
        optional_t(V&& v) : v(v), has{true} {}
        V value_or(V&& alt) const&
        {
            return has ? v : alt;
        }
        // etc.
    };
#endif
 
#include <iostream>
 
int main()
{
    if (has_optional > 0)
        std::cout << "<optional> is present\n";
    else if (has_optional < 0)
        std::cout << "<experimental/optional> is present\n";
    else
        std::cout << "<optional> is not present\n";
 
    optional_t<int> op;
    std::cout << "op = " << op.value_or(-1) << '\n';
    op = 42;
    std::cout << "op = " << op.value_or(-1) << '\n';
}

Ausgabe

<optional> is present
op = -1
op = 42

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 787 C++98 das Verhalten ist undefiniert, wenn eine Escape-Sequenz
in q-char-sequence oder h-char-sequence vorkommt
es ist bedingt unterstützt

[bearbeiten] Siehe auch

Eine Liste der Header-Dateien der C++-Standardbibliothek
C-Dokumentation für Source file inclusion