为什么库中的#define 变量在调用应用程序时被#define 覆盖?

Why #define variable in library is overridden from #define in calling application?

我正在尝试制作一个插件系统,它将有一个 header 文件供所有插件包含。其中 header 插件系统的版本在 #define 中定义如下:

PluginHeader.hpp:

#define PLUGIN_SYSTEM_VERSION "00.001"

class PluginSystem
{
public:
    string GetSystemVersion(){return PLUGIN_SYSTEM_VERSION; }
    void MyPluginDoStuff(){...}
}

我用这个 header 在 dll 中编译我的插件并将其导出。之后,我将它导入主应用程序,并将调用应用程序中#define 的值更改为“00.002”。如果我在 dll 中调用方法 GetSystemVersion,那么我将获得新值“00.002”。

这是预期的行为吗?如何让 dll 保持其定义的值?

这既不是预期的也不是意外的行为。你的程序有未定义的行为,所以任何结果(无论它看起来“正确”与否)都是可能的。

您的成员函数 PluginSystem::GetSystemVersion() 是在其 class 定义中定义(实现)的,因此是隐式内联的。

问题是,通过在不同的编译单元中对宏 PLUGIN_SYSTEM_VERSION 进行不同的定义(例如,在您的 DLL 和包含您的 header 的单独源文件中),您会导致您的程序在你的程序中有多个 PluginSystem::GetSystemVersion() 的定义(事实上,整个 class PluginSystem)。如果这些定义 不完全 相同,那么您就违反了 one-definition 规则。对于内联函数(以及 class),这意味着不同源文件看到的所有定义必须相同。

违反one-definition 规则意味着您的程序有未定义的行为。在不同的编译单元中看到不同版本的内联函数被调用(例如,在某些情况下调用 DLL 版本但在其他情况下不调用)是一种可能的症状。

如果你想在DLL中有函数,那么

  1. 更改 class 定义,使该函数不内嵌在 class 定义中,并确保 class 定义在任何地方都一致使用(在您的所有源文件中)程序,以及 DLL 的所有源文件中)- 例如,通过在需要的地方包含相同的 header;
  2. 在一个源文件中,对于 DLL,在 class 定义之外只包含一个函数定义。

虽然在技术上不是必需的,但我鼓励您避免在 header 中使用宏(除了包含守卫)(或者,甚至根本不使用宏 - 有其他选择)。如果您必须有宏 PLUGIN_SYSTEM_VERSION,请在本地将其定义到定义 PluginSystem::GetSystemVersion() 的单个源文件。这避免了通过在程序的不同部分使用不同的 PLUGIN_SYSTEM_VERSION(以及受其影响的代码)来混淆自己(并增加获得意外行为的机会)的可能性。