导出DLL中的静态数据

时间:2010-03-19 18:43:20

标签: c++ windows linker-errors dllexport

我有一个DLL,其中包含一个静态成员的类。我使用__declspec(dllexport)来使用此类的方法。但当我将它链接到另一个项目并尝试编译它时,我得到静态数据的“未解析的外部符号”错误。

e.g。 在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

我无法弄清楚如何解决这个问题。我究竟做错了什么?我怎样才能克服这些错误?

P.S。该代码最初是为Linux开发的,而.so /二进制组合可以正常运行

编辑:在给定的情况下,静态变量不是由应用程序直接引用,但是方法是内联的,因为它在标题中。我能够通过将方法移动到.cpp文件来解决链接错误。

5 个答案:

答案 0 :(得分:17)

在cprogramming.com的this主题中,建议静态变量是dll的本地变量而不是导出。

以下讨论摘要

静态成员不会被调用应用程序中的代码直接访问,只能通过dll中类的成员函数访问。但是,有几个内联函数访问静态成员。这些函数将内联扩展到调用应用程序代码中,使调用应用程序直接访问静态成员。这将违反上面引用的结果,即静态变量是dll的本地变量,无法从调用应用程序中引用。

答案 1 :(得分:10)

我的猜测是,使用DLL的类应该在标头中看到 dllimport 而不是 dllexport 。如果我是正确的,通常可以通过定义预处理器宏来实现,如:

#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

有意义吗?

答案 2 :(得分:3)

对于Windows DLL,__declspec(dllexport)__declspec(dllimport)之间存在特定区别,编译DLL时应使用dllexport,编译程序时应使用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

答案 3 :(得分:0)

尽管有总结,但可以从 DLL 中导出静态数据。但是,Visual Studio DLL 项目提供的标准宏出现了一个问题:

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

如果您有多个 DLL 从一个 DLL 到另一个或在 EXE 和 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;

答案 4 :(得分:-1)

为 c++17 使用内联 static inline std::string static_variable