Übersetzungseinheiten und Verknüpfungen
In einem C++-Programm kann ein Symbol, z. B. eine Variable oder ein Funktionsname, beliebig oft innerhalb des Bereichs deklariert werden. Sie kann jedoch nur einmal definiert werden. Diese Regel ist die "One Definition Rule" (ODR). Eine Deklaration führt einen Namen in das Programm ein (oder führt diesen wieder ein), zusammen mit genügend Informationen, um den Namen später einer Definition zuzuordnen. Eine Definition führt einen Namen ein und stellt alle zum Erstellen benötigten Informationen bereit. Wenn der Name eine Variable darstellt, erstellt eine Definition explizit Speicher und initialisiert sie. Eine Funktionsdefinition besteht aus der Signatur und dem Funktionstext. Eine Klassendefinition besteht aus dem Klassennamen gefolgt von einem Block, der alle Klassenmember auflistet. (Die Memberfunktionen können optional separat in einer anderen Datei definiert werden.)
Einige Deklarationen werden im folgenden Beispiel veranschaulicht:
int i;
int f(int x);
class C;
Das folgende Beispiel zeigt einige Definitionen:
int i{42};
int f(int x){ return x * i; }
class C {
public:
void DoSomething();
};
Ein Programm besteht aus einer oder mehreren Übersetzungseinheiten. Eine Übersetzungseinheit besteht aus einer Implementierungsdatei und allen Headern, die sie direkt oder indirekt enthält. Implementierungsdateien haben in der Regel eine Dateierweiterung von .cpp
oder .cxx
. Headerdateien haben in der Regel eine Erweiterung von .h
oder .hpp
. Jede Übersetzungseinheit wird unabhängig vom Compiler kompiliert. Nach Abschluss der Kompilierung führt der Linker die kompilierten Übersetzungseinheiten in einem einzigen Programm zusammen. Verstöße gegen die ODR-Regel werden in der Regel als Linkerfehler angezeigt. Verknüpfungsfehler treten auf, wenn derselbe Name in mehr als einer Übersetzungseinheit definiert ist.
Im Allgemeinen besteht die beste Möglichkeit, eine Variable in mehreren Dateien sichtbar zu machen, darin, sie in einer Headerdatei zu deklarieren. Fügen Sie dann in jeder .cpp
Datei, die die Deklaration erfordert, eine #include
Direktive hinzu. Durch Hinzufügen von Schutzvorrichtungen um den Kopfzeileninhalt stellen Sie sicher, dass die Namen, die ein Header deklariert, nur einmal für jede Übersetzungseinheit deklariert werden. Definieren Sie den Namen in nur einer Implementierungsdatei.
In C++20 werden Module als verbesserte Alternative zu Headerdateien eingeführt.
In einigen Fällen kann es erforderlich sein, eine globale Variable oder Klasse in einer .cpp
Datei zu deklarieren. In diesen Fällen benötigen Sie eine Möglichkeit, dem Compiler und Linker mitzuteilen, welche Art von Verknüpfung der Name hat. Der Typ der Verknüpfung gibt an, ob der Name des Objekts nur in einer Datei oder in allen Dateien sichtbar ist. Das Konzept der Verknüpfung gilt nur für globale Namen. Das Konzept der Verknüpfung gilt nicht für Namen, die innerhalb eines Bereichs deklariert sind. Ein Bereich wird durch eine Reihe von Klammern angegeben, z. B. in Funktions- oder Klassendefinitionen.
Externe und interne Verknüpfung
Eine freie Funktion ist eine Funktion, die im globalen oder Namespacebereich definiert ist. Nicht const globale Variablen und freie Funktionen weisen standardmäßig externe Verknüpfungen auf. Sie sind von jeder Übersetzungseinheit im Programm sichtbar. Kein anderes globales Objekt kann diesen Namen haben. Ein Symbol mit interner Verknüpfung oder keine Verknüpfung ist nur innerhalb der Übersetzungseinheit sichtbar, in der sie deklariert wird. Wenn ein Name über eine interne Verknüpfung verfügt, kann derselbe Name in einer anderen Übersetzungseinheit vorhanden sein. Variablen, die innerhalb von Klassendefinitionen oder Funktionstexten deklariert sind, weisen keine Verknüpfung auf.
Sie können erzwingen, dass ein globaler Name über eine interne Verknüpfung verfügt, indem Sie ihn explizit als static
deklarieren. Dieses Schlüsselwort beschränkt seine Sichtbarkeit auf dieselbe Übersetzungseinheit, in der es deklariert ist. In diesem Kontext bedeutet etwas static
anderes als bei anwendung auf lokale Variablen.
Die folgenden Objekte weisen standardmäßig eine interne Verknüpfung auf:
const
-Objekteconstexpr
-Objektetypedef
-Objektestatic
Objekte im Namespacebereich
Um einem Objekt eine const
externe Verknüpfung zuzuweisen, deklarieren Sie es als extern
einen Wert, und weisen Sie es einem Wert zu:
extern const int value = 42;
Weitere Informationen finden Sie unter extern
.