我有一些遗留代码,其中包含一些使用全局变量的构造函数注册自身的单例类.这是一个很大的代码库,它被编译成一个可执行文件.我已经try 组织代码库,并将代码重新组合到库中.当前代码的最小示例如下

Main.cpp

int main(int argc, char *argv[])
{
  return 0;
} 

Hash.cpp

#include <iostream>

class Hash
{
public:
    Hash()
    {
        std::cout << "Hash\n";
    }
};

Hash a;

而当前的构建配置是

CMakeLists.txt

cmake_minimum_required(VERSION 3.26)
project(mcve)

add_executable(mcve Main.cpp Hash.cpp)

构建代码并运行可执行文件打印

Hash

我已经将构建配置修改为

cmake_minimum_required(VERSION 3.26)
project(mcve)

add_library(Hash Hash.cpp)
add_executable(mcve Main.cpp)
target_link_libraries(mcve Hash)

这创建了静态库libHash.a并将其链接到可执行文件.编译相同的代码并运行可执行文件不会打印任何内容.为什么会有不同,在哪里有描述?它是C++标准的一部分还是编译器的一部分?它是特定于操作系统的(Linux静态库)吗?它是不是未定义的行为?

推荐答案

我想,应该在链接器的文档以及介绍静态库是什么、它们如何工作以及如何使用它们的介绍性教科书中描述它们之间的区别.

图中没有静态库:当翻译单元显式链接在一起时,其中的所有内容都成为可执行文件的一部分.

在您的第一个示例中,main.cpphash.cpp都链接到mcve可执行文件中,并且在启动时构造hash.cpp中的唯一全局对象.结局.

我重复一遍,与静态库的链接不会将101从静态库包含到可执行文件中.这不是静态库的工作方式.只有静态库中的单个转换单元导出与静态库链接的转换单元中未定义的符号--只有这些转换单元链接到可执行文件中(实际上,它稍微复杂一些,但对于这个问题来说,完全的复杂性并不重要,这只会使事情变得混乱,所以我们只使用这个简化的描述).这是什么是静态库的一个定义特征.

对所显示的代码进行非常非常仔细的判断后,我们会深刻地发现,hash.cpp导出的main.cpp个符号中没有未定义或未解析的符号.所以hash.cpp 104.全局对象是在hash.cpp中定义的,因此最终的可执行文件不会以程序运行时需要构造的任何全局对象结束.结局.

这并不是说静态库的初始化或构造规则发生变化.这是因为没有什么需要初始化或构造的.

Linux相关问答推荐

获取Perl文件::Tail开始在最后流传输文件

在Bluez/Linux中,周期性与连续蓝牙设备发现的已知缺陷是什么?

AddressSaniizer随机抛出没有任何解释的SIGSEGV

为什么我们不能使用${$#}来获取传递给shell 脚本的最后一个参数?

Linux-如何区分目录中名称相同但扩展名不同的所有文件

为什么waitpid(2)可以指定非子进程?

Linux BlueZ 5.65 hcitool 结合服务 UUID 和制造数据广告

如何验证所有 csv 文件是否具有相同的第一行?

将 Visual Studio C++ 项目迁移到 Linux 和 CMake

如何在 DolphinDB 中递归查找目录中的所有文件?

如何在bash中用另一个整数变量增加一个整数变量?

读取命令停止执行 bash 脚本

DMA 和内存映射 IO 有什么区别?

如何使用 GDB 和 QEMU 调试 Linux 内核?

如何使用 AWK 合并两个文件?

yum 可以告诉我哪些存储库提供了特定的包吗?

os.walk 没有隐藏文件夹

linux中netstat和ss的区别?

如何自动启动 Solr?

为嵌入式 Linux 设备实施更新/升级系统