静态成员变量在可执行文件和DLL之间不是全局的

时间:2018-05-08 06:54:45

标签: c++ linker

我的知识在链接DLL如何工作方面有点模糊,但我观察到对可执行文件中的静态成员变量的更改,该变量不会更改DLL中的相同静态成员变量。这是我的情景:

main.cpp静态链接到mylib.lib。在mylib.lib中,我有以下类:

// foo.h
class Foo
{
public:
    static int m_global;
    Foo();
    ~Foo();
};

// foo.cpp
#include "foo.h"

int Foo::m_global = 5;

我还有一个链接到mylib.lib的DLL,其中包含以下内容:

//testdll.h
#define MATHLIBRARY_API __declspec(dllimport)

void MATHLIBRARY_API printFoo();

// testdll.cpp
#include "testdll.h"
#include <iostream>

void printFoo() {
    std::cout << Foo::m_global << std::endl;
}

最后,在我的可执行文件的main.cpp中

// main.cpp
#include <iostream>
#include "testdll.h"
#include "foo.h"

int main() {
    std::cout << Foo::m_global << std::endl;
    Foo::m_global = 7;

    std::cout << Foo::m_global << std::endl;
    printMutiply();

    return 0;
}

我的预期输出是5,7,7。但是,我看到5,7,5这告诉我DLL没有看到静态成员变量更改。为什么会这样?如何让DLL看到可执行文件中的静态成员变量的变化?

2 个答案:

答案 0 :(得分:3)

信不信由你,但是你的应用程序违反了一个定义规则,因此触发了未定义的行为。您的program(在C ++标准中称为)最终具有Foo::m_global的双重定义 - 一个在可加载库中,另一个在main内。作为此未定义行为的可观察效果,​​Microsoft动态加载程序创建两个符号,一个来自可加载对象,另一个来自main。

在Linux中,ld(linux loader)实际上会将这些符号合并为一个(反过来会触发对非平凡对象的双重破坏)。

底线 - 不要在可加载库和可执行文件之间共享全局符号的定义。这适用于函数和变量,但共享函数通常没有明显的副作用,尽管技术上也是未定义的行为。

答案 1 :(得分:0)

这就是我们在项目中处理它的方式:

/* First a general definition which covers differences
 * of Windows and Linux for all of your libraries:
 */
#ifdef _WIN32
/* for Windows, Visual C++ */
#define MY_EXPORT __declspec(dllexport)
#define MY_IMPORT __declspec(dllimport)
#else /* _WIN32 */
/* for gcc */
#define MY_EXPORT __attribute__((visibility("default")))
#define MY_IMPORT __attribute__((visibility("default")))
#endif /* _WIN32 */

这必须为您的每个图书馆准备:

/* The API macro to distiguish two cases:
 * 1. DLL/Shared Object
 * 2. usage of DLL/Shared Object
 */
#ifdef BUILD_MY_LIB
#define  MY_LIB_API MY_EXPORT
#else /* BUILD_MY_LIB */
#define MY_LIB_API MY_IMPORT
#endif /* BUILD_MY_LIB */
然后在从MyLib库导出的任何MY_LIB_API中使用

class

class MY_LIB_API Foo {
};

其余的是使用编译器参数完成的:

  1. 要编译MyLib DLL或共享对象,-DBUILD_MY_LIB将添加到编译器的命令行参数中。

  2. 要使用DLL或共享对象,无需其他设置。

  3. 实际上,我们的解决方案也考虑了静态库。它将MY_LIB_API定义为空。但是,我们已经很久没有使用它了。因此,我把这部分留了下来。 (我必须承认我忘了它的工作原理......)

相关问题