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

发布于 2024-08-21 18:47:21 字数 1193 浏览 3 评论 0原文

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

I'm working on getting rLog to build as a DLL under windows, and I was getting undefined symbol errors relating to some global symbols in the rlog namespace. Specifically these in 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 );
...
 };

I assumed the problem was that 1) they weren't exported and 2) they weren't declared in the header so other things can access them. So I added a __declspec(dllexport) (via the RLOG_DECL macro) to them, and in the header, put:

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

But no matter how I declare the variables in RLogChannel.cpp I get a redefinition error, despite my externing them in the header... What's the right way to do this? Seems like it should be straightforward but I can't quite wrap my head around it.

Edit: error message

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

(same for all 4 symbols)

Edit: I don't know what happened, the code is exactly the same before but now it will compile (feels like MSVC weirdness...), unfortunately the symbols still show up as unresolved when linking into my library

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

早乙女 2024-08-28 18:47:21

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

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

希望有帮助。

One way to get around this problem is to define them once in one place and in the header.
But if you just shift all the definitions to the header you'll end up with the multiple definition problem.

A solution to that is this. Assuming the files are named 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"

The beauty of this solution is that because the definitions are only defined once in the project, you won't ever get them out of sync with each other and you only need to change them in one place. Imagine if you defined a variable as a long but in the extern definition it was declared as a short? you may end up with unexpected side effects. So doing it this way helps prevent these types of issues.

Hope that helps.

凉墨 2024-08-28 18:47:21

我认为马特非常接近。我曾经遇到过这个问题,并且是正确的(大多数可移植的解决方案是这样的:

--- (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 时,必须在符号声明和定义中匹配。另一方面,当外部world 使用您的库 - 它必须显示为 dllimport 符号


马切伊·雅布隆斯基

I think Matt is quite close. I had faced that issue some time a go and the correct (and most portable solutions is this:

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

The rule is simple. When you compile the dll that provides dllexport must be matched in both symbol declaration and definition. On the other hand when the outside world uses your library - it must appear to it as dllimport symbol.

Regards,
Maciej Jablonski

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文