如何在命名空间中正确使用extern?

时间:2010-02-11 21:02:36

标签: c++ dll namespaces extern

我正在努力让rLog在windows下构建为DLL,并且我得到了与rlog命名空间中的某些全局符号相关的未定义符号错误。特别是在RLogChannel.cpp:

namespace rlog {
...
  RLogChannel *_RLDebugChannel   = GetGlobalChannel( "debug",   Log_Debug );
  RLogChannel *_RLInfoChannel    = GetGlobalChannel( "info",    Log_Info );
  RLogChannel *_RLWarningChannel = GetGlobalChannel( "warning", Log_Warning );
  RLogChannel *_RLErrorChannel   = GetGlobalChannel( "error",   Log_Error );
...
 };

我认为问题在于1)它们没有被导出,2)它们没有在标题中声明,因此其他东西可以访问它们。所以我在它们中添加了__declspec(dllexport)(通过RLOG_DECL宏),并在标题中添加:

namespace rlog {
...
  RLOG_DECL extern RLogChannel *_RLDebugChannel;
  RLOG_DECL extern RLogChannel *_RLInfoChannel;
  RLOG_DECL extern RLogChannel *_RLWarningChannel;
  RLOG_DECL extern RLogChannel *_RLErrorChannel;
...
};

但无论我如何在RLogChannel.cpp中声明变量,我都会得到一个重新定义错误,尽管我在标题中对它们进行了外设...这样做的正确方法是什么?看起来它应该是直截了当但我无法完全绕过它。

编辑:错误消息

  Error 12  error C2086: 'rlog::RLogChannel *rlog::_RLDebugChannel' : redefinition  rlog-1.4\rlog\RLogChannel.cpp   45  rlog

(所有4个符号都相同)

编辑:我不知道发生了什么,代码完全相同,但现在它将编译(感觉像MSVC奇怪......),遗憾的是,当链接到我的库时,符号仍然显示为未解析

2 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是在一个位置和标题中定义它们一次。 但是如果你只是将所有定义转移到标题,你最终会遇到多重定义问题。

解决方案就是这样。假设这些文件名为rlog.c& rlog.h

--- (rlog.h) ---
#ifdef RLOG_DEFINES
#define EXTERN
#else
#define EXTERN extern
#endif


namespace rlog {
...
  RLOG_DECL EXTERN RLogChannel *_RLDebugChannel;
  RLOG_DECL EXTERN RLogChannel *_RLInfoChannel;
  RLOG_DECL EXTERN RLogChannel *_RLWarningChannel;
  RLOG_DECL EXTERN RLogChannel *_RLErrorChannel;
...
};


--- (rlog.c) ---
#define RLOG_DEFINES
#include "rlog.h"

...

--- (other .c files) ---
#include "rlog.h"

这个解决方案的优点在于,因为定义只在项目中定义一次,所以您不会让它们彼此不同步,您只需要在一个地方更改它们。想象一下,如果你将变量定义为long,但在extern定义中它被声明为short?你最终会出现意想不到的副作用。所以这样做有助于防止这些类型的问题。

希望有所帮助。

答案 1 :(得分:1)

我认为马特非常接近。我曾经有一段时间面对这个问题并且正确(而且最便携的解决方案就是这样:

--- (rlog.h) ---
#ifdef RLOG_DEFINES
#define RLOG_DECL __declspec(dllexport)
#else
#define RLOG_DECL __declspec(dllimport)
#endif


namespace rlog {
...
  RLOG_DECL extern RLogChannel *_RLDebugChannel;
  RLOG_DECL extern RLogChannel *_RLInfoChannel;
  RLOG_DECL extern RLogChannel *_RLWarningChannel;
  RLOG_DECL extern RLogChannel *_RLErrorChannel;
...
};


--- (rlog.c) ---
#define RLOG_DEFINES
#include "rlog.h"

namespace rlog {
...
  __declspec(dllexport) RLogChannel *_RLDebugChannel   = GetGlobalChannel( "debug",   Log_Debug );
  __declspec(dllexport) RLogChannel *_RLInfoChannel    = GetGlobalChannel( "info",    Log_Info );
  __declspec(dllexport) RLogChannel *_RLWarningChannel = GetGlobalChannel( "warning", Log_Warning );
  __declspec(dllexport) RLogChannel *_RLErrorChannel   = GetGlobalChannel( "error",   Log_Error );
...
 };


--- (other .c files) ---
#include "rlog.h"

规则很简单。编译提供dllexport的dll时,必须在符号声明和定义中进行匹配。另一方面,当外面的世界使用你的图书馆时 - 它必须显示为dllimport符号。

此致 Maciej Jablonski