【问题标题】:What happens to static variables when libraries are statically linked静态链接库时静态变量会发生什么
【发布时间】:2016-04-28 08:18:29
【问题描述】:

假设我有库 (A) 实现单例模式(它的实现中有一个静态变量)。

(A) 库被编译为静态库。

现在,假设我的 probject 中有:

  • (B),另一个静态库与(A) 静态链接。
  • (C),另一个静态库与(A) 静态链接。
  • (D),与(B)(C) 链接的顶级程序。

最后,我的单例真的是单例吗(而我的变量真的是静态的)? (B)(C) 是否从 (A) 看到相同的静态变量(它是 unic)吗?或者(A) 被静态链接两次嵌入(A) 的代码两次最终导致我来自(A) 的静态变量在最终的二进制代码中出现两次?那么如果(B)修改了静态变量值,(C)就看不到变化了?

注意:我在将项目库更改为静态链接而不是动态链接时遇到过这种情况。我只是想知道我是否做错了什么,或者这是否是一种正常的已知行为。

【问题讨论】:

  • 静态库基本上只是一个目标文件的存档,它像任何其他目标文件一样链接到输出文件。
  • (D) 如果需要来自 (A) 的符号,也必须链接到 (A)。 (B) 和 (C) 不包含 (A) 代码。如果 (B) 和 (C) 是 dlls/sos 会有所不同。
  • 您的前两个步骤没有意义。静态库是目标代码模块的集合;它们没有“链接”到其他静态库。他们只是“在那里”。在构建 (D) 时,我看不到仅链接 (B) 和 (C) 将如何产生最终产品。当拉入需要另一个静态库的静态库时,拉取者(可执行文件的链接)有责任填写空白(在这种情况下,也链接在(A)中),这应该告诉你一些关于您的最终作品中有多少 (A)。
  • @WhozCraig:为了解决这个问题,我以(D) 链接到(A)(B)(C) 结束。但我记得遇到过(B)(C) 没有看到(A) 的静态变量的相同值的情况((B) 会在此处写入一个值,而(C) 不会看到该值发生变化)。据我记得,当(A)(B)(C) 链接时,我经历过……但现在我很难重现。
  • @jpo38 如果 (B) 和 (C) 是 dynamic 模块(DLL、.so 等)并且 (A) 是 static 库。只要 (D) 不直接使用仅在 (A) 中的资源,上述相同配置也将允许您声明的 (D) 链接仅指向 (B) 和 (C)。

标签: c++ static static-libraries static-linking


【解决方案1】:

首先:

(B) 和 (C) 不链接到 (A)。静态库是编译的,而不是链接的。 在构建 (B) 和 (C) 时,编译器可能需要查看 (A) 中的某些定义,但不要将其与链接混淆。 (A) 代码不会复制到 (B) 或 (C) 中。

其次:

(D) 必须链接到 (A)、(B) 和 (C)。这意味着您在 (D) 中只能获得一份 (A) 代码。

动态链接库/共享对象:

如果 (B) 和 (C) 是 dlls/sos,这当然会有所不同。 Dll 是链接的,因此如果您将 (B) 和 (C) 构建为 dll 并将它们与 (A) 链接,那么您将在 (B) 和 (C) 中拥有 (A) 代码的单独副本。

(B) 和 (C) 是否从 (A) 获取相同的静态变量

这取决于您的变量是否有external or internal linkage。以下头文件包含一个具有内部链接的静态 int 变量。这意味着包含此文件的每个翻译单元都将获得自己的 myVariable 副本。

//MyHeader.h
#pragma once
static int myVariable = 0;

【讨论】:

  • 感谢 Mohamad,这是有道理的。
  • 你知道如何给Msvc下的静态库中的静态成员变量提供外部链接吗?或者如果不能强制 D 使用已经包含在 B 或 C 中的 A 的功能?
【解决方案2】:

静态链接库,与静态变量无关。

一个静态变量,在当前编译范围之外是不可见的(.o 文件中没有创建符号名称,因此没有其他 .o 文件可以通过符号名称找到该变量)。

这意味着变量

静态int foo;可以存在于每个编译范围中,并且每个都是唯一的

【讨论】:

    【解决方案3】:

    您的静态变量确实是静态的。我怀疑即使 (B) 链接 (A),(B) 也不会获取它自己的 (A) 副本,而是包含 (A) 应该链接的信息。

    但是,可以在两个库中使用静态变量编译相同的源代码 - 例如:

    test.cpp:

    int g_myGlobal = 23;
    

    并在 (A) 和 (B) 静态库中编译它,但是当链接整个应用程序或 dll 时 - 您将收到关于双重定义静态变量的链接器错误。

    如果你使用 static 关键字声明变量:

    test.cpp:

    static int g_myGlobal = 23;
    

    然后,如果从 (A) 和 (B) 链接相同的源代码 - 它将被编译和链接正常,但结果您将拥有 g_myGlobal 变量的两个实例(甚至可以不同)。

    【讨论】:

      猜你喜欢
      • 2020-11-05
      • 2023-03-20
      • 2012-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多