C++ 如何在名称空间中正确使用extern?

C++ 如何在名称空间中正确使用extern?,c++,dll,namespaces,extern,C++,Dll,Namespaces,Extern,我正在努力让rLog在windows下构建为一个DLL,并且我在rLog名称空间中遇到了与一些全局符号相关的未定义符号错误。特别是在RLogChannel.cpp中: namespace rlog { ... RLogChannel *_RLDebugChannel = GetGlobalChannel( "debug", Log_Debug ); RLogChannel *_RLInfoChannel = GetGlobalChannel( "info", Log_

我正在努力让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怪异…),不幸的是,当链接到我的库时,符号仍然显示为未解决的符号

解决此问题的一种方法是在一个位置和标题中定义一次。 但是,如果您只是将所有定义移到标题,那么最终将出现多定义问题

解决办法是这样。假设文件名为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?你可能会有意想不到的副作用。因此,这样做有助于防止此类问题


希望这能有所帮助。

我认为马特很接近。一段时间以来,我一直面临着这个问题,正确的(最便携的)解决方案是:

--- (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

确切的错误消息是什么?在上面进行了更新,因此它的格式比我在这里发布的要好一些。似乎问题中遗漏了一些重要的内容。您能否提供一个简洁完整的测试用例(例如,一个我可以按原样传递给编译器的文件)这就产生了这个错误?关于您上次的编辑:它有助于重建所有文件,因为有时旧文件会缓存在MSVC中。您将RLOG_DECL翻转为指定导入,而不是在代码中导出链接到您的DLL,对吗?他已经说他在cpp文件中定义了它们一次,并在标题中声明了它们。在c文件还意味着它们在项目中只定义一次。包括该文件的头(带有声明)保证您不会出现意外的不匹配,因为如果您这样做,编译器将给出错误。简言之,我看不出您提供的代码有什么好处,但它的缺点是更复杂,并且不遵循正常惯例。@gct-检查您的makefile和linker标志…也许您链接了两次什么东西?我不知道是什么问题是的,我最终说去它的,然后去了一个静态链接