36

静的メンバーを持つクラスを含むDLLがあります。__declspec(dllexport)このクラスのメソッドを利用するために使用します。しかし、それを別のプロジェクトにリンクしてコンパイルしようとすると、静的データに対して「未解決の外部シンボル」エラーが発生します。

例:DLLでは、Test.h

class __declspec(dllexport) Test{
protected:
    static int d;
public:
    static void m(){int x = a;}
}

DLLでは、Test.cpp

#include "Test.h"

int Test::d;

Testを使用するアプリケーションでは、m()を呼び出します。

また、メソッドごとに__declspec(dllexport)を個別に使用しようとしましたが、静的メンバーに対して同じリンクエラーが発生します。

dumpbinを使用してDLL(.lib)を確認すると、シンボルがエクスポートされていることがわかります。

たとえば、アプリはリンク時に次のエラーを出します。

1>Main.obj : error LNK2001: unresolved external symbol "protected: static int CalcEngine::i_MatrixRow" (?i_MatrixRow@CalcEngine@@1HA)

ただし、.libのdumpbinには次のものが含まれています。

Version      : 0
  Machine      : 14C (x86)
  TimeDateStamp: 4BA3611A Fri Mar 19 17:03:46 2010
  SizeOfData   : 0000002C
  DLL name     : CalcEngine.dll
  Symbol name  : ?i_MatrixRow@CalcEngine@@1HA (protected: static int CalcEngine::i_MatrixRow)
  Type         : data
  Name type    : name
  Hint         : 31
  Name         : ?i_MatrixRow@CalcEngine@@1HA

これを解決する方法がわかりません。私は何が間違っているのですか?これらのエラーをどのように克服できますか?

PSコードは元々Linux用に開発されており、.so/binaryの組み合わせは問題なく機能します

編集:与えられたケースでは、静的変数はアプリケーションによって直接参照されませんが、メソッドはヘッダーにあるためインライン化されます。メソッドを.cppファイルに移動することで、リンクエラーを解決できました。

4

5 に答える 5

19

cprogramming.comのこのスレッドでは、静的変数がdllに対してローカルであり、エクスポートされないことが推奨されています。

以下の議論の要約

静的メンバーは、呼び出し元のアプリケーションのコードから直接アクセスされるのではなく、dll内のクラスのメンバー関数を介してのみアクセスされます。ただし、静的メンバーにアクセスするインライン関数がいくつかあります。これらの関数は、呼び出し元のアプリケーションが静的メンバーに直接アクセスできるように、呼び出し元のアプリケーションコードにインライン展開されます。これは、静的変数がdllに対してローカルであり、呼び出し元のアプリケーションから参照できないという上記の結果に違反します。

于 2010-03-19T19:08:56.600 に答える
16

私の推測では、DLLを使用するクラスでは、ヘッダーにdllexportではなくdllimportが表示されるはずです。私が正しければ、これは通常、次のようなプリプロセッサマクロを定義することで実現できます。

#ifdef EXPORTING
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif

次に、それをクラス宣言で使用します。

class DECLSPEC Test{
protected:
    static int d;
public:
    static void m(){}
}

そのため、Test.cpp(またはDLLプロジェクトで意味のある場所)で、dllexportでエクスポートされるようにエクスポートするように指定できます

#define EXPORTING
#include "Test.h"

int Test::d;

EXPORTINGを定義していない他のプロジェクトでは、dllimportが表示されます。

それは意味がありますか?

于 2010-03-19T19:06:08.747 に答える
5

__declspec(dllexport)Windows DLLでは、 vs__declspec(dllimport)の間に特定の違いがありdllexport、DLLをコンパイルするときにdllimport使用する必要があり、このDLLにリンクするプログラムをコンパイルするときに使用する必要があります。これを定義する標準的な方法は、マクロを使用することです。

以下は、ビジュアルスタジオの例です。

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the DLL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// DLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
于 2010-03-19T19:26:41.887 に答える
0

要約にもかかわらず、DLLから静的データをエクスポートできます。ただし、VisualStudioDLLプロジェクトによって提供される標準マクロで発生する問題があります。

#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif

あるDLLから別のDLLへ、またはEXEとDLLの間でコードを呼び出す複数のDLLがある場合、すべてのヘッダーがエクスポートされるため、このマクロに問題が発生します。__declspecを処理する一意のマクロが必要です。この問題を処理する最も安全な方法は次のとおりです。

#ifdef MYPROJECT_DLL_EXPORTS
     #define MYPROJECT_API __declspec(dllexport)
#else
     #define MYPROJECT_API __declspec(dllimport)
#endif

次に、DLLプロジェクトのコンパイラプリプロセッサオプションでのみ、MYPROJECT_APIを定義します。ヘッダーコード:

struct/class MYPROJECT_API myclass {
   static int counter;
};

そして、.cppファイルでは:

int myclass::counter = 0;
于 2021-03-12T17:09:19.920 に答える
-2

c++17にはインラインを使用する static inline std::string static_variable

于 2021-06-30T23:22:13.750 に答える