4

C++共有ライブラリプロジェクトのグローバル変数に問題があります。私のライブラリは、dllとしてだけでなく、標準のg ++​​共有ライブラリ(.so)としても機能する必要があります。私はファイルlibiup_dll.cppとlibiup_dll.hを作成することによってこれを行いました。

#ifdef BUILD_DLL

// code for the dll: wrapper functions around the classes in my shared library

#endif

私のdllには、関数setloglevel(int)とgeterrormsg()が必要です。すべてのクラスで、グローバル変数errormsgにすべてのエラーメッセージを追加します。この変数は、geterrormsg()関数によって返される必要があります。私はこれを使用して実装しました

std::string errormsg;
int loglevel;

libiup_dll.h(outsideおよび#ifdefsなので、グローバルに利用可能である必要があります)に入れてから、

extern std::string errormsg;
extern int loglevel;

私のクラスの.hファイル(クラスの外、ファイルの上部)

今私は2つの問題があります:

1)ライブラリを使用するg ++でコマンドラインプログラムをコンパイルすると、エラーが発生します

ターゲットの構築:libiup_test呼び出し:GCCC++リンカーg++-L "/ home / hilboll / src / libiup / Release" -L / usr / local / lib -o "libiup_test" ./src/stratcalc/SimpleStratosphericColumnCalculatorTest.o ./src/ interp / SimpleInterpolatorTest.o ./src/Test.o -lgsl -lhdf5 -lhdf5_cpp -lblas -liup /home/hilboll/src/libiup/Release/libiup.so:errormsgへの未定義の参照loglevel' /home/hilboll/src/libiup/Release/libiup.so: undefined reference to'collect2:ldが1つの終了ステータスを返しましたmake :***[libiup_test]エラー1

私のコマンドラインプログラムでは、errormsgやloglevelへの参照はまったくありません。

2)VS2008を使用してWindowsでdllをコンパイルしようとすると、

z:\ src \ vs \ libiup_dll \ libiup_dll.h(229):エラーC2086:'std :: string errormsg':Neudefinition z:\ src \ libiup \ src \ stratcalc ../ interp / SimpleInterpolator.h(16): Siehe Deklaration von'errormsg' z:\ src \ vs \ libiup_dll \ libiup_dll.h(234):エラーC2086:'int loglevel':Neudefinition z:\ src \ libiup \ src \ stratcalc ../ interp / SimpleInterpolator.h( 17):Siehe Deklaration von'loglevel'

私が理解している限り、VSは2つの変数を2回定義していると考えていることを意味します。ただし、SimpleInterpolator.h 16/17には、extern宣言のみがあります...

どういうわけか、グローバル変数がどのように機能するかをまだ理解していないようです。どんな助けでも大歓迎です!

4

4 に答える 4

4

グローバルは何度も宣言できますが、定義する必要があるのは1回だけです。

「extern」キーワードは、そうでなければ宣言としての定義となるものをマークします。

これを行う方法の一般的なイディオムは次のとおりです。

// In a header file (declaration)
extern int myGlobal;

// In a source file (definition)
int myGlobal;

次に、グローバルを参照する場合は、extern宣言を繰り返すか、すでにextern宣言が含まれているヘッダーファイルをインクルードする必要があります。

絶対にすべきでないことは、「int myGlobal」定義(「extern」なし)をヘッダーに入れることです。これを行うと、そのヘッダーを含むすべてのファイルが独自のmyGlobalを定義しようとし、リンク時にシンボルの競合が発生します。定義は、唯一のソースファイルに含める必要があります。extern宣言は、必要な数のファイルまたはヘッダーに表示できます。

特に、2つのエラーで何が起こっているかは次のとおりです。

  • Linuxでコンパイルする場合、グローバルを定義するDLLヘッダーはプリプロセッサー・マクロによって削除されるため、グローバルには宣言がありますが定義はなく、リンカーは文句を言います。
  • Windowsでコンパイルする場合、DLLヘッダーは複数のコンパイルユニット(ソースファイル)に含まれているため、グローバルには複数の定義があり、リンカーは文句を言います。
于 2009-08-24T15:35:46.383 に答える
4

秘訣は、各.cppファイルがコンパイル単位であること、つまりコンパイルされるものであることを知ることです。それぞれが完全な個人であり、お互いについて何も知りません。これらがまとめられるのは、リンク段階でのみです。

これで、externはコンパイルされたcppファイルに対して「この変数は他の場所にあります」と言います。コンパイラーはリンカーに参照ヒントを配置して整理します。

したがって、変数定義をヘッダーファイルに入れているので、そのヘッダーを2つ(またはそれ以上)のcppファイルにインクルードしている可能性があります。したがって、これらの各cppファイルは、コンパイルされると、実変数を持っていると見なされます。次に、リンカーがやって来て、あまりにも多くを認識します。

変数を独自のcppファイル(またはメインのcppファイル)に配置し、外部参照のみをヘッダーファイルに配置します。そうすれば、複数定義されたシンボルで大丈夫なはずです。

于 2009-08-24T15:38:10.453 に答える
1

あなたはあなたが持っていると言います:

std::string errormsg;
int loglevel;

libiup_dll.h外で#ifdefs。これは、libiup_dll.h(直接的または間接的に)複数回含まれている場合に問題となり、問題#2の原因である可能性があります。

ヘッダーが含まれている場合、これも問題#1の原因になる可能性があると思います。他の場所では使用しない場合でも、ヘッダーによってもたらされる変数の定義があります。

これらの2つの変数の定義は、通常、ヘッダーではなく、.cまたは.cppファイルに含める必要があります。これらのextern宣言をヘッダーに含めることは問題ありません。

于 2009-08-24T15:36:18.787 に答える
1

あなたが言った、

I implemented this by using

    std::string errormsg;
    int loglevel;

in libiup_dll.h (outside and #ifdefs, so it should be globally available),
and then putting

    extern std::string errormsg;
    extern int loglevel;

in my classes' .h files (outside the class, at the top of the files)

代わりに、任意の数のヘッダーファイルを使用して変数を宣言してから、1つだけのCまたはCPPファイルでexternなしで変数を定義する必要があると思います。extern

于 2009-08-24T15:36:35.680 に答える