C'est une différence assez célèbre entre les systèmes Windows et Unix.
Peu importe ce que:
- Chaque processus a son propre espace d'adressage, ce qui signifie qu'il n'y a jamais de mémoire partagée entre les processus (sauf si vous utilisez une bibliothèque ou des extensions de communication inter-processus).
- La règle de définition unique (ODR) s'applique toujours, ce qui signifie que vous ne pouvez avoir qu'une seule définition de la variable globale visible au moment de la liaison (liaison statique ou dynamique).
Donc, le problème clé ici est vraiment la visibilité .
Dans tous les cas, static
les variables globales (ou fonctions) ne sont jamais visibles de l'extérieur d'un module (dll / so ou exécutable). Le standard C ++ exige qu'ils aient un lien interne, ce qui signifie qu'ils ne sont pas visibles à l'extérieur de l'unité de traduction (qui devient un fichier objet) dans lequel ils sont définis. Donc, cela règle ce problème.
Là où cela se complique, c'est lorsque vous avez extern
des variables globales. Ici, les systèmes Windows et Unix sont complètement différents.
Dans le cas de Windows (.exe et .dll), les extern
variables globales ne font pas partie des symboles exportés. En d'autres termes, différents modules ne sont en aucun cas conscients des variables globales définies dans d'autres modules. Cela signifie que vous obtiendrez des erreurs de l'éditeur de liens si vous essayez, par exemple, de créer un exécutable qui est censé utiliser une extern
variable définie dans une DLL, car cela n'est pas autorisé. Vous devrez fournir un fichier objet (ou bibliothèque statique) avec une définition de cette variable extern et lier statiquement avec à la fois l'exécutable et la DLL, résultant en deux variables globales distinctes (une appartenance à l'exécutable et un appartenant à la DLL ).
Pour exporter réellement une variable globale sous Windows, vous devez utiliser une syntaxe similaire à la syntaxe d'export / import de la fonction, à savoir:
#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;
Lorsque vous faites cela, la variable globale est ajoutée à la liste des symboles exportés et peut être liée comme toutes les autres fonctions.
Dans le cas des environnements de type Unix (comme Linux), les bibliothèques dynamiques, appelées "objets partagés" avec extension, .so
exportent toutes extern
les variables globales (ou fonctions). Dans ce cas, si vous effectuez une liaison au moment du chargement de n'importe où vers un fichier objet partagé, alors les variables globales sont partagées, c'est-à-dire liées ensemble comme une seule. Fondamentalement, les systèmes de type Unix sont conçus pour faire en sorte qu'il n'y ait pratiquement aucune différence entre la liaison avec une bibliothèque statique ou dynamique. Encore une fois, l'ODR s'applique à tous les niveaux: une extern
variable globale sera partagée entre les modules, ce qui signifie qu'elle ne devrait avoir qu'une seule définition sur tous les modules chargés.
Enfin, dans les deux cas, pour les systèmes Windows ou de type Unix, vous pouvez effectuer une liaison d' exécution de la bibliothèque dynamique, c'est-à-dire en utilisant soit LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
soit dlopen()
/ dlsym()
/ dlclose()
. Dans ce cas, vous devez obtenir manuellement un pointeur vers chacun des symboles que vous souhaitez utiliser, et qui inclut les variables globales que vous souhaitez utiliser. Pour les variables globales, vous pouvez utiliser GetProcAddress()
ou dlsym()
tout simplement la même chose que pour les fonctions, à condition que les variables globales fassent partie de la liste de symboles exportée (selon les règles des paragraphes précédents).
Et bien sûr, comme une note finale nécessaire: les variables globales doivent être évitées . Et je crois que le texte que vous avez cité (à propos des choses "peu claires") fait référence exactement aux différences spécifiques à la plate-forme que je viens d'expliquer (les bibliothèques dynamiques ne sont pas vraiment définies par le standard C ++, c'est un territoire spécifique à la plate-forme, ce qui signifie qu'il est beaucoup moins fiable / portable).