【学习日记】静态库与动态库的区别及使用指南

文章目录

静态库与动态库的区别及使用指南

本文将详细介绍这两种库的定义、工作原理、优缺点及使用示例。

静态库

定义

静态库是一组预编译的对象文件的集合,这些对象文件在编译期间被链接到程序中。静态库通常具有 .a 扩展名(在 Unix 系统上)或 .lib 扩展名(在 Windows 系统上)。

使用方式

  1. 创建静态库

    • 将源代码文件编译成对象文件(.o 文件)。
    • 使用归档工具(如 ar 在 Unix 系统上)将这些对象文件打包成一个静态库(.a 文件)。
  2. 链接静态库

    • 在编译应用程序时,链接器将静态库中的代码与应用程序的代码进行链接,生成一个独立的可执行文件。
    • 这个可执行文件包含了所有必要的代码,可以在没有外部库的环境中运行。

优点

  1. 性能:静态链接在编译时完成,不需要在运行时加载库文件,使得程序启动和运行速度更快。
  2. 独立性:生成的可执行文件包含了所有所需的代码,可以在没有原始库的环境中运行。
  3. 版本控制:库的版本在编译时确定,避免了运行时的兼容性问题。

缺点

  1. 文件大小:静态链接会增加最终可执行文件的大小,因为所有库代码都被包含进去。
  2. 更新困难:如果静态库中的代码有更新,需要重新编译所有使用该库的程序。
  3. 重复内容:多个使用相同静态库的程序会包含库的副本,导致磁盘空间浪费。

使用示例

假设我们有两个源文件,math_functions.cppstring_functions.cpp,它们分别实现了一些数学和字符串操作函数。

cpp 复制代码
// math_functions.cpp
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

// string_functions.cpp
#include <string>

std::string concatenate(const std::string& a, const std::string& b) {
    return a + b;
}
创建静态库
  1. 编译源文件为对象文件:

    sh 复制代码
    g++ -c math_functions.cpp string_functions.cpp
  2. 使用 ar 工具创建静态库:

    sh 复制代码
    ar rcs libmylibrary.a math_functions.o string_functions.o
使用静态库

假设我们有一个主程序 main.cpp,需要使用静态库中的函数:

cpp 复制代码
// main.cpp
#include <iostream>
#include <string>

extern int add(int a, int b);
extern int subtract(int a, int b);
extern std::string concatenate(const std::string& a, const std::string& b);

int main() {
    std::cout << "Add: " << add(2, 3) << std::endl;
    std::cout << "Subtract: " << subtract(5, 3) << std::endl;
    std::string result = concatenate("Hello, ", "world!");
    std::cout << "Concatenate: " << result << std::endl;
    return 0;
}

编译并链接主程序与静态库:

sh 复制代码
g++ main.cpp -L. -lmylibrary -o myprogram

运行程序:

sh 复制代码
./myprogram

动态库

定义

动态库是在程序运行时加载的库。动态库通常具有 .so 扩展名(在 Unix 系统上)或 .dll 扩展名(在 Windows 系统上)。

工作原理

  1. 创建动态库

    • 将源代码文件编译成对象文件,使用 -fPIC 选项生成位置无关代码。
    • 使用编译器生成共享对象文件(.so 文件)。
  2. 链接动态库

    • 在编译期间,只需建立一个符号链接,实际的库代码在程序运行时加载。

优点

  1. 文件大小:由于库代码不在可执行文件中,可执行文件会比较小。
  2. 更新方便:动态库可以独立于应用程序进行更新。只需更新库文件,不需要重新编译依赖该库的程序。

缺点

  1. 运行时依赖:生成的可执行文件在运行时需要找到并加载动态库文件。如果库文件缺失,程序将无法运行。
  2. 性能:由于库在程序运行时加载,可能会影响程序启动速度。

使用示例

假设我们有一个动态库 libmylib.so,其包含了一些数学函数。

创建动态库
  1. 编译源文件为对象文件:

    sh 复制代码
    g++ -fPIC -c math_functions.cpp
  2. 创建动态库:

    sh 复制代码
    g++ -shared -o libmylib.so math_functions.o
使用动态库

假设我们有一个主程序 main.cpp,需要使用动态库中的函数:

cpp 复制代码
// main.cpp
#include <iostream>
#include <string>

extern int add(int a, int b);
extern int subtract(int a, int b);
extern std::string concatenate(const std::string& a, const std::string& b);

int main() {
    std::cout << "Add: " << add(2, 3) << std::endl;
    std::cout << "Subtract: " << subtract(5, 3) << std::endl;
    std::string result = concatenate("Hello, ", "world!");
    std::cout << "Concatenate: " << result << std::endl;
    return 0;
}

编译并链接主程序与动态库:

sh 复制代码
g++ main.cpp -L. -lmylib -o myprogram

运行时设置 LD_LIBRARY_PATH 环境变量来指定动态库的位置:

sh 复制代码
export LD_LIBRARY_PATH=.
./myprogram

如何区分静态库和动态库

  1. 文件扩展名 :静态库通常是 .a.lib,动态库通常是 .so.dll
  2. 编译和链接命令
    • 静态库:在编译命令中使用 -l 选项链接静态库。
    • 动态库:在编译命令中使用 -l 选项链接动态库,并在运行时需要找到库文件。
  3. 可执行文件依赖
    • 静态库:生成的可执行文件不依赖外部库文件。
    • 动态库:生成的可执行文件在运行时需要找到并加载库文件。

总结

  • 静态库:在编译期间被链接到程序中,生成的可执行文件包含库代码。
  • 动态库:在程序运行时加载,生成的可执行文件依赖外部库文件。

封面

使用 DALL-E-3 生成。

相关推荐
序属秋秋秋1 小时前
《C++初阶之内存管理》【内存分布 + operator new/delete + 定位new】
开发语言·c++·笔记·学习
许白掰1 小时前
Linux入门篇学习——Linux 工具之 make 工具和 makefile 文件
linux·运维·服务器·前端·学习·编辑器
B1nna2 小时前
Docker学习
学习·docker·容器
promising-w8 小时前
【运算放大器专题】基础篇
嵌入式硬件·学习
宝山哥哥8 小时前
网络信息安全学习笔记1----------网络信息安全概述
网络·笔记·学习·安全·网络安全
前端开发与ui设计的老司机8 小时前
从UI设计到数字孪生实战:构建智慧教育的个性化学习平台
学习·ui
X Y O8 小时前
神经网络初步学习3——数据与损失
人工智能·神经网络·学习
十秒耿直拆包选手8 小时前
Qt:主窗体(QMainwindow)初始化注意事项
c++·qt
霖0010 小时前
C++学习笔记三
运维·开发语言·c++·笔记·学习·fpga开发
mit6.82410 小时前
[shad-PS4] Vulkan渲染器 | 着色器_重新编译器 | SPIR-V 格式
c++·游戏引擎·ps4