C语言动态库与静态库编译测试示例详细介绍终结篇

 C语言动态库与静态库编译链接时的详细对比与示例

下面我将提供更详细的示例,并通过对比表格清晰地展示静态库和动态库的特性差异以及它们之间的各种链接关系。

## 1. 静态库与动态库特性对比

| 特性                | 静态库(.a/.lib)                     | 动态库(.so/.dll)                     |
|---------------------|------------------------------------|-------------------------------------|
| **链接时机**         | 编译时链接                         | 运行时链接                          |
| **文件大小**         | 可执行文件较大                     | 可执行文件较小                      |
| **内存占用**         | 每个进程独立占用                   | 多个进程可共享                      |
| **更新方式**         | 需重新编译整个程序                 | 只需替换库文件                      |
| **加载速度**         | 启动快                             | 启动稍慢(需加载动态库)              |
| **依赖管理**         | 无运行时依赖                       | 需确保运行时库存在                  |
| **兼容性**           | 与编译环境严格匹配                 | 需考虑ABI兼容性                     |
| **默认扩展名(Linux)**| .a                                 | .so                                 |
| **默认扩展名(Windows)**| .lib                              | .dll                                |

## 2. 详细示例场景

### 2.1 基础文件准备

**common.h** (公共头文件):
```c
#ifndef COMMON_H
#define COMMON_H

void static_func();
void dynamic_func();
void helper_func();

#endif
```

**helper.c** (辅助函数):
```c
#include <stdio.h>
#include "common.h"

void helper_func() {
    printf("Helper function called\n");
}
```

### 2.2 场景1:纯静态库使用

**static_lib.c**:
```c
#include <stdio.h>
#include "common.h"

void static_func() {
    printf("Static library function\n");
    helper_func();  // 调用辅助函数
}
```

编译步骤:
```bash
# 编译辅助函数
gcc -c helper.c -o helper.o

# 编译静态库
gcc -c static_lib.c -o static_lib.o
ar rcs libstatic.a static_lib.o helper.o

# 编译主程序
gcc main.c -L. -lstatic -o static_main
```

### 2.3 场景2:纯动态库使用

**dynamic_lib.c**:
```c
#include <stdio.h>
#include "common.h"

void dynamic_func() {
    printf("Dynamic library function\n");
    helper_func();  // 调用辅助函数
}
```

编译步骤:
```bash
# 编译动态库
gcc -c -fPIC helper.c -o helper.o
gcc -c -fPIC dynamic_lib.c -o dynamic_lib.o
gcc -shared -o libdynamic.so dynamic_lib.o helper.o

# 编译主程序
gcc main.c -L. -ldynamic -o dynamic_main

# 设置库路径并运行
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./dynamic_main
```

## 3. 混合链接场景

### 3.1 静态库链接动态库

**static_with_dynamic.c**:
```c
#include <stdio.h>
#include "common.h"

void static_uses_dynamic() {
    printf("Static function calling dynamic:\n");
    dynamic_func();  // 调用动态库函数
}
```

编译步骤:
```bash
# 先编译动态库(使用前面的libdynamic.so)
# 编译静态库
gcc -c static_with_dynamic.c -o static_with_dynamic.o
ar rcs libstatic_with_dynamic.a static_with_dynamic.o

# 编译主程序(需要同时链接静态库和动态库)
gcc main_mixed.c -L. -lstatic_with_dynamic -ldynamic -o mixed_main
```

### 3.2 动态库链接静态库

**dynamic_with_static.c**:
```c
#include <stdio.h>
#include "common.h"

void dynamic_uses_static() {
    printf("Dynamic function calling static:\n");
    static_func();  // 调用静态库函数
}
```

编译步骤:
```bash
# 先编译静态库(使用前面的libstatic.a)
# 编译动态库
gcc -c -fPIC dynamic_with_static.c -o dynamic_with_static.o
gcc -shared -o libdynamic_with_static.so dynamic_with_static.o -L. -lstatic

# 编译主程序
gcc main_mixed.c -L. -ldynamic_with_static -o dynamic_with_static_main
```

## 4. 复杂依赖场景

### 4.1 静态库依赖另一个静态库

**static_lib2.c**:
```c
#include <stdio.h>

void static_func2() {
    printf("Second level static function\n");
}
```

编译步骤:
```bash
# 编译二级静态库
gcc -c static_lib2.c -o static_lib2.o
ar rcs libstatic2.a static_lib2.o

# 修改一级静态库使用二级静态库
# 重新编译一级静态库
gcc -c static_lib.c -o static_lib.o
ar rcs libstatic.a static_lib.o -L. -lstatic2

# 编译主程序
gcc main.c -L. -lstatic -o static_chain_main
```

### 4.2 动态库依赖另一个动态库

**dynamic_lib2.c**:
```c
#include <stdio.h>

void dynamic_func2() {
    printf("Second level dynamic function\n");
}
```

编译步骤:
```bash
# 编译二级动态库
gcc -c -fPIC dynamic_lib2.c -o dynamic_lib2.o
gcc -shared -o libdynamic2.so dynamic_lib2.o

# 修改一级动态库使用二级动态库
# 重新编译一级动态库
gcc -c -fPIC dynamic_lib.c -o dynamic_lib.o
gcc -shared -o libdynamic.so dynamic_lib.o -L. -ldynamic2

# 编译主程序
gcc main.c -L. -ldynamic -o dynamic_chain_main

# 需要设置两个库的路径
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./dynamic_chain_main
```

## 5. 链接关系总结表

| 链接场景                  | 命令示例                                      | 注意事项                                  |
|--------------------------|---------------------------------------------|------------------------------------------|
| **纯静态库**             | `gcc main.c -L. -lstatic -o static_main`    | 所有代码最终都在可执行文件中              |
| **纯动态库**             | `gcc main.c -L. -ldynamic -o dynamic_main`  | 需要设置LD_LIBRARY_PATH                  |
| **静态库使用动态库**     | `gcc main.c -L. -lstatic_with_dynamic -ldynamic` | 静态库只包含对动态库的引用                |
| **动态库使用静态库**     | `gcc -shared -o libdyn_with_stat.so dyn.o -L. -lstatic` | 静态库代码会被合并到动态库中              |
| **静态库链式依赖**       | `ar rcs libstatic1.a static1.o -L. -lstatic2` | 使用ar命令的依赖需要特别注意              |
| **动态库链式依赖**       | `gcc -shared -o libdyn1.so dyn1.o -L. -ldyn2` | 运行时需要所有依赖库都在LD_LIBRARY_PATH中 |

## 6. 高级技巧

1. **查看依赖关系**:
   ```bash
   # Linux查看动态库依赖
   ldd your_program
   
   # 查看静态库内容
   ar -t libstatic.a
   nm libstatic.a
   ```

2. **版本控制**:
   ```bash
   # 带版本的动态库
   gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0 foo.c
   ln -s libfoo.so.1.0 libfoo.so.1
   ln -s libfoo.so.1 libfoo.so
   ```

3. **RPATH设置**:
   ```bash
   # 编译时设置运行时库搜索路径
   gcc -Wl,-rpath=/path/to/libs -L/path/to/libs -lfoo -o program
   ```

4. **符号可见性控制**:
   ```c
   // 在头文件中使用
   #define PUBLIC_API __attribute__((visibility("default")))
   PUBLIC_API void my_public_function();
   ```

这些示例和对比应该能够帮助你全面理解C语言中静态库和动态库的各种使用场景和它们之间的复杂关系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/79948.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

神经网络:节点、隐藏层与非线性学习

神经网络&#xff1a;节点、隐藏层与非线性学习 摘要&#xff1a; 神经网络是机器学习领域中一种强大的工具&#xff0c;能够通过复杂的结构学习数据中的非线性关系。本文从基础的线性模型出发&#xff0c;逐步深入探讨神经网络中节点和隐藏层的作用&#xff0c;以及它们如何…

POI创建Excel文件

文章目录 1、背景2、创建表格2.1 定义表头对象2.2 Excel生成器2.3 创建模板2.4 处理Excel表头2.5 处理Excel内容单元格样式2.6 处理单个表头 3、追加sheet4、静态工具5、单元测试6、完整代码示例 1、背景 需求中有需要用户自定义Excel表格表头&#xff0c;然后生成Excel文件&a…

【分布式系统中的“瑞士军刀”_ Zookeeper】三、Zookeeper 在实际项目中的应用场景与案例分析

在分布式系统日益复杂的当下&#xff0c;Zookeeper 凭借强大的协调能力成为众多项目的关键组件。本篇文章将结合实际项目场景&#xff0c;详细介绍 Zookeeper 在电商秒杀、微服务架构、分布式配置管理以及大数据处理集群等领域的应用&#xff0c;以及在不同的案例场景下的具体分…

【翻译、转载】MCP 提示 (Prompts)

原文地址&#xff1a;https://modelcontextprotocol.io/docs/concepts/prompts#python 提示 (Prompts) 创建可重用的提示模板和工作流 提示 (Prompts) 使服务器能够定义可重用的提示模板和工作流&#xff0c;客户端可以轻松地将其呈现给用户和 LLM。它们提供了一种强大的方式来…

accept() reject() hide()

1. accept() 用途 确认操作&#xff1a;表示用户完成了对话框的交互并确认了操作&#xff08;如点击“确定”按钮&#xff09;。 关闭模态对话框&#xff1a;结束 exec() 的事件循环&#xff0c;返回 QDialog::Accepted 结果码。适用场景 模态对话框&#xff08;通过 exec()…

如何查看电脑IP地址和归属地:全面指南

在数字化时代&#xff0c;了解自己电脑的IP地址和归属地信息变得越来越重要。无论是进行网络故障排查、远程办公设置&#xff0c;还是出于网络安全考虑&#xff0c;掌握这些基本信息都很有必要。本文将详细介绍如何查看电脑的公网IP、内网IP以及归属地信息&#xff0c;并提供常…

基于python生成taskc语言文件--时间片轮询

目录 前言 utf-8 chinese GB2312 utf-8 排除task.c chinese GB2312 排除task.c 运行结果 前言 建议是把能正常工作的单个功能函数放到一起&#xff08;就和放while函数里的程序一样&#xff09;&#xff0c;程序会按顺序自动配置。 不同的格式已经对应给出。 utf-8 impo…

Docker手动重构Nginx镜像,融入Lua、Redis功能

核心内容&#xff1a;Docker重构Nginx镜像&#xff0c;融入Lua、Redis功能 文章目录 前言一、准备工作1、说明2、下载模块3、Nginx配置文件3、Dockerfile配置文件3、准备工作全部结束 二、构建镜像三、基于镜像创建容器三、lua脚本的redis功能使用总结 前言 ⁣⁣⁣⁣ ⁣⁣⁣⁣…

DeepSeek+Excel:解锁办公效率新高度

目录 一、引言&#xff1a;Excel 遇上 DeepSeek二、认识 DeepSeek&#xff1a;大模型中的得力助手2.1 DeepSeek 的技术架构与原理2.2 DeepSeek 在办公场景中的独特优势 三、DeepSeek 与 Excel 结合的准备工作3.1 获取 DeepSeek API Key3.2 配置 Excel 环境 四、DeepSeekExcel 实…

解决Vue2------You may use special comments to disable some warnings.问题

问题截图 解决办法 打开项目中.eslintrc.js在rules中&#xff0c;添加以下代码&#xff0c;并extends的 vue/standard注释掉 space-before-function-paren: 0, semi: off, quotes : off, comma-dangle : off, vue/comment-directive: off

数据集-目标检测系列- 牙刷 检测数据集 toothbrush >> DataBall

数据集-目标检测系列- 牙刷 检测数据集 toothbrush >> DataBall DataBall 助力快速掌握数据集的信息和使用方式。 贵在坚持&#xff01; * 相关项目 1&#xff09;数据集可视化项目&#xff1a;gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/over…

解决:前后端跨域请求

目录 关于跨域请求出现的原因 同源策略 示例&#xff08;跨域问题&#xff09; 如何解决跨域请求 方法一&#xff1a;配置后端服务器以允许跨域请求&#xff08;后端&#xff09; 方法二&#xff1a;使用代理服务器&#xff08;前端&#xff09; 一 &#xff0c;使用aja…

AI内容检测的技术优势与应用场景

随着互联网的普及和数字内容的爆发式增长&#xff0c;文本、图片、音频、视频等多样化内容已成为信息传播的主要载体。然而&#xff0c;伴随内容增长的是违法违规信息的泛滥&#xff0c;如涉黄、涉政、虚假广告、恶意引流等&#xff0c;不仅威胁用户体验&#xff0c;还对平台合…

DockerDesktop替换方案

背景 由于DockerDesktop并非开源软件&#xff0c;如果在公司使用&#xff0c;可能就有一些限制&#xff0c;那是不是除了使用DockerDesktop外&#xff0c;就没其它办法了呢&#xff0c;现在咱们来说说替换方案。 WSL WSL是什么&#xff0c;可自行百度&#xff0c;这里引用WS…

『Linux_网络』 基于状态机的Connect断线重连

客户端会面临服务器崩溃的情况&#xff0c; 我们可以试着写一个客户端重连的代码&#xff0c; 模拟并理 解一些客户端行为&#xff0c; 比如游戏客户端等。 客户端部分&#xff0c;我们本次采用状态机的设计模式实现 下面是关于状态机模式的介绍 状态机模式 状态机模式&…

5月6日日记

一点心得是 看通知要仔细认真&#xff0c;自己想问的问题要先看看通知或者文件中说了没有&#xff0c;如果没说再去问相关负责人。 上课的教室一定要看好&#xff0c;看准了再去。别像今天一样先去了科技楼又去了工学馆。 线代开课了。感觉总体还行&#xff0c;并不是很难。…

【算法专题十】哈希表

文章目录 0.哈希表简介1. 两数之和1.1 题目1.2 思路1.3 代码 2.判断是否为字符重排2.1 题目2.2 思路2.3 代码 3. leetcode.217.存在重复元素3.1 题目3.2 思路3.3 代码 4. leetcode.219.存在重复的元素Ⅱ4.1 题目4.2 思路4.3 代码 5. leetcode.49.字母异位词分组5.1 题目5.2 思路…

【前缀和】矩阵区域和

文章目录 1314. 矩阵区域和解题思路1314. 矩阵区域和 1314. 矩阵区域和 ​ 给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和: i - k <= r <= i + k, j - k <= c <= j + k …

MyBatis的SQL映射文件中,`#`和`$`符号的区别

在MyBatis的SQL映射文件中,#和$符号用于处理SQL语句中的参数替换,但它们的工作方式和使用场景有所不同。 #{} 符号 预编译参数:#{} 被用来作为预编译SQL语句的占位符。这意味着MyBatis会将你传入的参数设置为PreparedStatement的参数,从而防止SQL注入攻击,并允许MyBatis对…

Linux中为某个进程临时指定tmp目录

起因&#xff1a; 在linux下编译k8s&#xff0c;由于编译的中间文件太多而系统的/tmp分区设置太小&#xff0c;导致编译失败&#xff0c;但自己不想或不能更改/tmp分区大小&#xff0c;所以只能通过其他方式解决。 现象&#xff1a; tmp分区大小&#xff1a; 解决方法&#x…