これは、WindowsとUnixライクなシステムのかなり有名な違いです。
何があっても:
- 各プロセスには独自のアドレス空間があります。つまり、プロセス間でメモリが共有されることはありません(プロセス間通信ライブラリまたは拡張機能を使用しない限り)。
- 一つの定義規則(ODR)はまだあなたが唯一のリンク時(静的または動的リンク)で見えるグローバル変数の一つの定義を持つことができることを意味し、適用されます。
したがって、ここでの重要な問題は本当に可視性です。
すべての場合において、static
グローバル変数(または関数)がモジュール(dll / soまたは実行可能ファイル)の外部から見えることはありません。C ++標準では、これらが内部リンケージを持っている必要があります。つまり、これらは、それらが定義されている(オブジェクトファイルになる)変換単位の外部には表示されません。それで、それはその問題を解決します。
複雑になるのは、extern
グローバル変数がある場合です。ここでは、WindowsとUnixのようなシステムは完全に異なります。
Windows(.exeおよび.dll)の場合、extern
グローバル変数はエクスポートされたシンボルの一部ではありません。つまり、異なるモジュールは、他のモジュールで定義されたグローバル変数をまったく認識しません。これは、たとえばextern
DLLで定義された変数を使用することになっている実行可能ファイルを作成しようとすると、リンカーエラーが発生することを意味します。これは許可されていないためです。オブジェクトファイル(または静的ライブラリ)にそのextern変数の定義を提供し、実行可能ファイルとDLLの両方に静的にリンクする必要があります。その結果、2つの異なるグローバル変数(1つは実行可能ファイルに属し、もう1つはDLLに属します) )。
Windowsでグローバル変数を実際にエクスポートするには、関数export / import構文と同様の構文を使用する必要があります。
#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;
これを行うと、グローバル変数がエクスポートされたシンボルのリストに追加され、他のすべての関数と同様にリンクできます。
Unixのような環境(Linuxなど)の場合、「共有オブジェクト」と呼ばれる動的ライブラリは、拡張子が.so
すべてのextern
グローバル変数(または関数)をエクスポートします。この場合、どこからでも共有オブジェクトファイルにロード時リンクを行うと、グローバル変数が共有されます。つまり、1つにリンクされます。基本的に、Unixライクなシステムは、静的ライブラリと動的ライブラリのリンクに実質的に違いがないように設計されています。繰り返しますが、ODRは全面extern
的に適用されます。つまり、グローバル変数はモジュール間で共有されます。つまり、ロードされたすべてのモジュールにわたって1つの定義のみを持つ必要があります。
最後に、どちらの場合も、WindowsまたはUnixライクなシステムでは、動的ライブラリのランタイムリンクを実行できます。つまり、LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
またはdlopen()
/ dlsym()
/ を使用できますdlclose()
。その場合、使用する各シンボルへのポインタを手動で取得する必要があります。これには、使用するグローバル変数が含まれます。グローバル変数の場合は、使用することができますGetProcAddress()
かdlsym()
あなたはグローバル変数は、(前の段落のルールによる)、エクスポートシンボルリストの一部であることは、機能のために行うとちょうど同じ。
そしてもちろん、必要な最後の注記として、グローバル変数は避けるべきです。そして、あなたが引用したテキスト(「不明確」なことについて)は、先ほど説明したプラットフォーム固有の違いを正確に参照していると思います(動的ライブラリはC ++標準では実際には定義されていません。これはプラットフォーム固有の領域であり、つまり信頼性が低い/ポータブルです)。