Dies ist ein ziemlich berühmter Unterschied zwischen Windows- und Unix-ähnlichen Systemen.
Egal was:
- Jeder Prozess verfügt über einen eigenen Adressraum. Dies bedeutet, dass zwischen den Prozessen niemals Speicher gemeinsam genutzt wird (es sei denn, Sie verwenden eine prozessübergreifende Kommunikationsbibliothek oder -erweiterungen).
- Die One Definition Rule (ODR) gilt weiterhin, dh Sie können nur eine Definition der globalen Variablen zum Zeitpunkt der Verknüpfung anzeigen (statische oder dynamische Verknüpfung).
Das Hauptproblem hier ist also die Sichtbarkeit .
In allen Fällen sind static
globale Variablen (oder Funktionen) niemals von außerhalb eines Moduls (dll / so oder ausführbar) sichtbar. Der C ++ - Standard verlangt, dass diese über eine interne Verknüpfung verfügen, was bedeutet, dass sie außerhalb der Übersetzungseinheit (die zu einer Objektdatei wird), in der sie definiert sind, nicht sichtbar sind. Damit ist das Problem gelöst.
Kompliziert wird es, wenn Sie extern
globale Variablen haben. Hier sind Windows- und Unix-ähnliche Systeme völlig unterschiedlich.
Bei Windows (.exe und .dll) sind die extern
globalen Variablen nicht Teil der exportierten Symbole. Mit anderen Worten, verschiedene Module kennen in keiner Weise globale Variablen, die in anderen Modulen definiert sind. Dies bedeutet, dass Sie Linkerfehler erhalten, wenn Sie beispielsweise versuchen, eine ausführbare Datei zu erstellen, die eine extern
in einer DLL definierte Variable verwenden soll , da dies nicht zulässig ist. Sie müßten eine Objektdatei (oder statische Bibliothek) mit einer Definition dieser externen Variablen bieten und sie verknüpfen statisch mit sowohl der ausführbaren Datei und den DLL, in zwei verschiedenen globalen Variablen resultierende (eine Zugehörigkeit zu der ausführbaren Datei und einem an den DLL gehör ).
Um eine globale Variable in Windows tatsächlich zu exportieren, müssen Sie eine Syntax verwenden, die der Funktion Export / Import-Syntax ähnelt, dh:
#ifdef COMPILING_THE_DLL
#define MY_DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define MY_DLL_EXPORT extern "C" __declspec(dllimport)
#endif
MY_DLL_EXPORT int my_global;
Wenn Sie dies tun, wird die globale Variable zur Liste der exportierten Symbole hinzugefügt und kann wie alle anderen Funktionen verknüpft werden.
In Unix-ähnlichen Umgebungen (wie Linux) .so
exportieren die dynamischen Bibliotheken, die als "gemeinsam genutzte Objekte" mit der Erweiterung bezeichnet werden, alle extern
globalen Variablen (oder Funktionen). In diesem Fall werden die globalen Variablen gemeinsam genutzt, dh wenn sie während der Ladezeit von einer beliebigen Stelle aus mit einer gemeinsam genutzten Objektdatei verknüpft werden. Grundsätzlich sind Unix-ähnliche Systeme so konzipiert, dass es praktisch keinen Unterschied zwischen der Verknüpfung mit einer statischen oder einer dynamischen Bibliothek gibt. Auch hier gilt ODR auf der ganzen Linie: Eine extern
globale Variable wird von allen Modulen gemeinsam genutzt, was bedeutet, dass sie nur eine Definition für alle geladenen Module haben sollte.
In beiden Fällen können Sie für Windows- oder Unix-ähnliche Systeme die dynamische Bibliothek zur Laufzeit verknüpfen, dh entweder mit LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
oder dlopen()
/ dlsym()
/ dlclose()
. In diesem Fall müssen Sie manuell einen Zeiger auf jedes der Symbole erhalten, die Sie verwenden möchten, und dies schließt die globalen Variablen ein, die Sie verwenden möchten. Für globale Variablen können Sie Funktionen verwenden GetProcAddress()
oder dlsym()
genauso verwenden wie für Funktionen, vorausgesetzt, die globalen Variablen sind Teil der exportierten Symbolliste (gemäß den Regeln der vorherigen Absätze).
Und natürlich als notwendige letzte Anmerkung: Globale Variablen sollten vermieden werden . Und ich glaube, dass der von Ihnen zitierte Text (über "unklare" Dinge) genau auf die plattformspezifischen Unterschiede verweist, die ich gerade erklärt habe (dynamische Bibliotheken sind nicht wirklich durch den C ++ - Standard definiert, dies ist plattformspezifisches Gebiet, was bedeutet ist viel weniger zuverlässig / tragbar).