静态库中的外部指针为空,当不是静态库时工作正常

Posted

技术标签:

【中文标题】静态库中的外部指针为空,当不是静态库时工作正常【英文标题】:Extern pointer is null in static library, worked fine when not a static library 【发布时间】:2016-08-17 16:31:30 【问题描述】:

我将我的 Visual Studio 项目(2015,C++)分成三部分:

静态库中的主应用程序 只有一个主函数的可执行文件 使用静态 .lib 文件的单元测试,以便他们可以导入所需的类并对它们进行单元测试。

在我将其拆分为 lib/exe/tests 之前,主应用程序只是一个独立的可执行文件,并且运行良好。

现在我无法仅使用 main 函数运行可执行文件,也无法进行单元测试,因为某个指针始终为空。唯一的主要区别是我在这个例子中使用了一个原始指针,但是我在我的代码中使用了一个 unique_ptr(但是目前我切换到原始指针只是为了确保下面这个例子尽可能准确并且它没有'不要使用原始指针神奇地编译/运行)。

代码看起来与以下非常相似(多余的代码已被删除):

// console.hpp
extern Console *console;

实现cpp文件(只需要):

// console.cpp
Console *console = new Console();

现在在一些不相关的函数中,由于控制台指针为空指针,此代码失败:

// some_other_file.cpp
#include "console.hpp"

    // Inside some function...
    console->doSomething();  // console is NULL

同样,我在一个项目中完美运行的代码很好。无论如何,即使它已被分成 3 部分,它也可以正常编译,没有链接错误,但现在该指针始终为空。

作为最后一个有趣的说明,全局和外部的非指针变量确实有效。这是否仅限于指针/unique_ptrs?

这可以通过单例模式解决吗?

【问题讨论】:

这与我使用的设置相同。我不确定如何重现。你说控制台是在main之前初始化的全局变量吗?你试过断点吗?也许初始化函数可以解决这个问题。 您是在项目设置中添加了库,还是仅包含头文件?再想一想,如果您没有链接该库,您会收到 console 的链接错误,所以它必须是其他东西...... 这会导致链接错误,而不是运行时问题。 @Water Console *console = new Console(); -- 您确定这是您拥有的确切代码吗? console 与您的 extern 变量不同,后者恰好具有相同的名称。 @PaulMcKenzie 我复制粘贴了它。但是我认为您正在做一些事情,似乎在不让全局变量初始化的主函数之前调用了其他代码。有没有办法确保在使用之前设置变量?我不知道这是否需要更改代码以使用单例模式,或者是否有办法确保 console 在其他所有操作之前运行(我目前不知道该怎么做)。 【参考方案1】:

线索就在这条评论中:“似乎在主函数之前调用了其他代码,这些代码不会让全局变量初始化。”

引用console 的代码可能作为另一个全局初始化的一部分运行,在这种情况下,它发生在console 的初始化之前。您必须非常小心,以确保您不依赖于全局初始化程序的顺序。在拆分程序之前,您可能很幸运,现在您的运气已经用完了。

修复它的最简单方法是使用单例模式。不是让程序的其他部分直接引用指针,而是让它们调用一个返回指针的函数,该函数将在第一次初始化它。这样可以确保在使用之前对其进行初始化。

这是一个常见的模式:

Console *GetConsole() 
    static Console *console = new Console();
    return console;

现在控制台不再是一个全局变量。所有想要访问控制台的东西都调用GetConsole

函数局部静态变量将在函数第一次调用时被初始化,之后它只是返回值。如果您有多个线程和较旧的编译器,则必须做更多的工作来防止可能的竞争条件。现代编译器应该以线程安全的方式进行初始化。

【讨论】:

以上是关于静态库中的外部指针为空,当不是静态库时工作正常的主要内容,如果未能解决你的问题,请参考以下文章

如何防止静态库中的所有符号加载以及为什么在链接静态库时导出相同.o文件中的其他符号进行测试

从 C++ 中的共享库调用指向列表的静态指针

当 iOS 应用程序链接到静态库时,如何获取丢弃的符号列表?

当我链接动态库而不是静态库时,CMake 有效

是否可以使用现有的第三方框架(如 metaio 框架)创建静态库

打包静态库时如何隐藏标题?