[解決済み] 共有ライブラリを動的リンクした場合、共有ライブラリ内のグローバル変数とスタティック変数はどうなりますか?
質問
グローバルと静的変数を持つモジュールがアプリケーションに動的にリンクされているときに何が起こるかを理解しようとしています。 モジュールというのは、ソリューションの各プロジェクトを意味します(私はビジュアルスタジオでよく仕事をします!)。これらのモジュールは、*.lib、*.dll、または*.exe自体に組み込まれています。
アプリケーションのバイナリは、データセグメント(およびconstの場合は読み取り専用データセグメント)に、すべての個々の翻訳ユニット(オブジェクトファイル)のグローバルおよび静的データを含んでいると理解しています。
-
このアプリケーションで、ロードタイム・ダイナミックリンクを行うモジュールAを使用する場合はどうなりますか?DLLにはグローバルとスタティックのためのセクションがあると思います。オペレーティングシステムはそれらをロードしますか?もしそうなら、それらはどこにロードされるのでしょうか?
-
また、アプリケーションがランタイム・ダイナミック・リンクでモジュールBを使用する場合はどうなるのでしょうか?
-
アプリケーションにAとBの2つのモジュールを使用する場合、AとBのグローバルのコピーは以下のように作成されますか(それらが異なるプロセスの場合)?
-
DLL A と B は、アプリケーションのグローバルにアクセスできますか?
(理由も併せて記載してください)
引用元 MSDN :
DLL のソースコード・ファイル内でグローバル変数として宣言された変数は、コンパイラとリンカによってグローバル変数として扱われますが、特定の DLL をロードする各プロセスは、その DLL のグローバル変数のコピーを独自に取得します。静的変数のスコープは、その静的変数が宣言されたブロックに限定されます。その結果、各プロセスは、デフォルトで DLL のグローバル変数と静的変数の独自のインスタンスを持つことになります。
とから これ :
モジュールを動的にリンクする場合、異なるライブラリがグローバルの独自のインスタンスを持っているのか、それともグローバルが共有されているのかが不明確になることがあります。
ありがとうございます。
どのように解決するのですか?
これはWindowsとUnix系システムの違いとして、かなり有名な話です。
何があっても
- それぞれの プロセス は独自のアドレス空間を持ち、プロセス間でメモリが共有されることはありません(プロセス間通信ライブラリや拡張機能を使用した場合を除く)。
- は 1つの定義ルール (ODR) はまだ適用されます。つまり、リンク時に見えるグローバル変数の定義は 1 つだけです (静的リンクまたは動的リンク)。
つまり、ここでの重要な問題は、本当に 視認性 .
すべての場合において
static
グローバル変数(または関数)は、モジュール(dll/soまたは実行ファイル)の外からは決して見えません。C++の標準では、これらは内部リンクを持つことが要求されています。つまり、それらが定義されている翻訳ユニット(オブジェクトファイルになる)の外からは見えないということです。つまり、この問題は解決されたのです。
複雑になるのは
extern
グローバル変数です。ここで、WindowsとUnix系は全く別物です。
Windows(.exeと.dll)の場合は
extern
グローバル変数はエクスポートされたシンボルの一部ではありません。つまり、異なるモジュールは、他のモジュールで定義されたグローバル変数を一切意識することがないのです。つまり、例えば、あるモジュールで定義されたグローバル変数を使うはずの実行ファイルを作ろうとすると、リンカエラーが発生します。
extern
というのも、DLLで定義された変数を使用することはできないからです。オブジェクトファイル(またはスタティックライブラリ)にextern変数を定義して、それを静的にリンクする必要があります。
ともに
その結果、2 つの異なるグローバル変数 (1つは実行ファイルに属するもの、もう1つは DLL に属するもの) が発生します。
Windowsで実際にグローバル変数をエクスポートするには、関数のエクスポート/インポート構文と同様の構文、つまり、:
#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など)の場合、ダイナミックライブラリは、拡張子が"shared objects"と呼ばれます。
.so
エクスポートオール
extern
グローバル変数(または関数)を使用します。この場合、もしあなたが
ロードタイム
は、どこからでも共有オブジェクトファイルにリンクされるため、グローバル変数は共有される、つまり、1つのものとしてリンクされることになります。基本的にUnix系のシステムでは、スタティックライブラリでリンクしてもダイナミックライブラリでリンクしても、ほとんど差がないように設計されています。ここでも、ODRは全面的に適用されます。
extern
グローバル変数はモジュール間で共有されます。つまり、ロードされるすべてのモジュールで1つの定義しか持たないはずです。
最後に、WindowsまたはUnixライクなシステムの場合、どちらのケースでも
実行時
ダイナミック・ライブラリのリンク、すなわち
LoadLibrary()
/
GetProcAddress()
/
FreeLibrary()
または
dlopen()
/
dlsym()
/
dlclose()
. その場合、使用したいシンボルへのポインタをそれぞれ手動で取得する必要があり、それには使用したいグローバル変数も含まれます。グローバル変数については
GetProcAddress()
または
dlsym()
関数と同じように、グローバル変数がエクスポートされたシンボルリストの一部であれば、(前の段落の規則によって)大丈夫です。
そしてもちろん、必要な最後の注意として。 グローバル変数は避けるべき . そして、あなたが引用した文章(物事が "曖昧であることについて)は、まさに私が先ほど説明したプラットフォーム固有の差異を指していると思います(ダイナミックライブラリは実際には C++ 標準で定義されておらず、これはプラットフォーム固有の領域です、つまり信頼性と移植性がはるかに低いということです)。
関連
-
[解決済み】識別子 "string "は未定義?
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み】テンプレートの引数1が無効です(Code::Blocks Win Vista) - テンプレートは使いません。
-
[解決済み] 既に.objで定義されている-二重包含はない
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] スタティック・ライブラリとシェアード・ライブラリの違い?
-
[解決済み】スタティックリンクとダイナミックリンクの比較
-
[解決済み】共有オブジェクト(.so)、静的ライブラリ(.a)、DLL(.so)の違い?)
-
[解決済み】「静的リンク」「動的リンク」の意味とは?
-
[解決済み】CやC++で静的変数はどこに格納されているのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】テンプレートの引数1が無効です(Code::Blocks Win Vista) - テンプレートは使いません。
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる