前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C语言---静态库VS动态库

C语言---静态库VS动态库

作者头像
HeaiKun
发布于 2020-07-07 03:23:32
发布于 2020-07-07 03:23:32
9.1K00
代码可运行
举报
文章被收录于专栏:HeaiKunHeaiKun
运行总次数:0
代码可运行

“本文都是在Linux环境下操作。”

在编程的过程中,使用已经封装好的库函数是十分方便的,也是十分高效的,因此会使用函数库是很重要的。在C语言中,函数库文件分为两种类型,一种是静态库(库程序是直接注入目标程序的,不分彼此,库文件通常以.a结尾),另一种是动态库(库程序是在运行目标程序时(中)加载的,库文件通常以.so结尾),下面我们就探索一下这两种库文件的特点和使用方式吧!

背景知识

我们要先了解一下源文件到可执行文件的编译过程如下图:

预编译

预编译是使用预编译器cpp进行处理.c源文件和.h头文件,最终生成一个.i的文件。预编译过程就是处理源代码中以#开头的预编译指令,如#include #define 等。预编译过程等价于如下命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc -E hello.c -o hello.i  
或则   
cpp hello.c > hello.i 

#include 就是将包含的头文件全部展开到#include的位置,所以一个.c源文件如果包含多个头文件,头文件的顺序是需要注意的地方。

编译

编译的过程就是将 预处理 完的文件进行一系列的词法分析、语法分析、语义分析及优化,最后生成 .s 汇编代码文件。编译过程等价如下命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc -S hello.i -o hello.s    

编译过程是整个程序构建的核心部分,也是最复杂的部分之一。

汇编

汇编器是将汇编代码转变成机器可以执行的指令, 每一条汇编代码几乎都对应着一条机器指令。最后生成一个 .o 目标文件。汇编过程等价如下命令:

gcc -c hello.s -o hello.o 或者 as hello.s -o hello.o

汇编器的汇编过程相对简单一些,只需要根据汇编指令和机器指令对照表一一翻译就可以了。

链接

链接的作用就是我们这篇文章的重点,就是将我们编译出来的目标文件和我们代码所用到的库文件一起打包成一个可执行文件的过程。例如hello.c中的打印函数printf,这个函数不是凭空出现的,在链接的过程中就要连同对应库文件一起打包,最终可执行文件才能正常运行。

静态库VS动态库

静态库和动态库的载入时间是不一样的。

静态库的代码在编译的过程中已经载入到可执行文件中,所以最后生成的可执行文件相对较大。

动态库的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,所以最后生成的可执行文件相对较小。

静态库和动态库的最大区别是,静态库链接的时候把库直接加载到程序中,而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度和降低程序的耦合度。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。

静态库

静态库的名字一般是libxxx.a 在编译的时候直接编译进可执行文件中,运行环境中可以不用存在库文件,但是如果库文件更新了,可执行文件需要重新编译。

操作静态库

Linux下使用ar命令进行操作静态库:

ar archivefile objfile

archivefile:archivefile是静态库的名称

objfile: objfile是已.o为扩展名的中间目标文件名,可以多个并列

参数 意义

-r 将objfile文件插入静态库尾或者替换静态库中同名文件

-x 从静态库文件中抽取文件objfile

-t 打印静态库的成员文件列表

-d 从静态库中删除文件objfile

-s 重置静态库文件索引

-v 创建文件冗余信息

-c 创建静态库文件

编译静态库

在编译成静态库之前,我们需要将源文件编译一下,生成一个 .o 文件的目标文件。例如写了一个打印helloworld的接口,我们要先执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc -c hello.c
ar crv libhello.a hello.o

第一条命令是生成目标文件hello.o ,第二条命令是将目标文件hello.o 打包成静态库文件libhello.a。

链接静态库

上面我们说了静态库是如何生成的,然后我们说一下静态库怎么使用。静态库是要编译进可执行文件的,在程序运行的环境中,并不需要静态库的存在。比如我们生成的静态库文件是libhello.a 需要编译的文件是main.c。编译命令如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc main.c -L . -lhello 

解读一下: -L 后面是静态库文件所在的目录,我这里 . 就是指当前目录的意思。也就是库文件就和源文件在同一路径。真正编译的时候,这个路径还是要填绝对路径要好,这个需要注意一下。后面的-l加上库名,这个库名是去掉lib和后面的.a。静态库的链接就是这样的。

动态库

动态库中的代码是可执行文件在运行中加载执行的,也就是说 程序运行环境中要有动态库文件。一般动态库文件命名为lib***.so。动态库的优点就是方便升级,动态库变化了,可执行文件不用重新编译。

编译动态库

还拿hello.c来说,使用下面的命令就可以生成一个动态库文件libhello.so 。看一下各个参数的含义。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 gcc -fPIC -shared -o libhello.so hello.c

-fPIC 是创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。-shared指定生成动态链接库。

调用动态库态库

我们在运行环境中直接运行可执行文件,前提动态库文件也在运行环境中。需要注意的是 系统在运行程序的时候,需要知道动态库的名称和位置,这样才能加载,如果找不到动态库就会直接程序退出报错。

所以在编译程序的时候使用下面方式编译:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gcc mian.c -o mian -L ./ -lhello

同样,-L后面是库文件的路径,最好是用绝对路径。-l加上去掉lib的库名。然后直接执行可执行文件就可以了。

还用一种使用动态库的方式是:

linux提供dlopen、dlsym、dlerror和dlcolose函数获取动态链接库的函数。通过这个四个函数可以实现一个插件程序,方便程序的扩展和维护。函数格式如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <dlfcn.h>

void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
Link with -ldl.

就是使用这些函数去找对应的库函数入口地址,然后去执行。具体详细内容可自行Google学习。

参考文档:

https://www.cnblogs.com/Anker/p/3527677.html

https://blog.csdn.net/qq_41786318/article/details/79545018

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HeaiKun 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux编译工具:gcc入门
1. 什么是gcc gcc的全称是GNU Compiler Collection,它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器(GNU C Compiler),现在除了c语言,还支持C++、java、Pascal等语言。gcc支持多种硬件平台。 2. gcc的特点 gcc是一个可移植的编译器,支持多种硬件平台。例如ARM、X86等等。 gcc不仅是个本地编译器,它还能跨平台交叉编译。所谓的本地编译器,是指编译出来的程序只能够在本地环境进行运行。而gcc编译出来的程序能够在其他平台进行运
Tencent JCoder
2018/07/02
5K0
【C语言系列】C语言编译流程分析
前几天看了《程序员的自我修养——链接、装载与库》中的第二章“编译和链接”,主要根据其中的内容简单总结一下C程序编译的过程吧。 我现在一般都是用gcc,所以自然以GCC编译hellworld为例,简单总结如下。 hello.c源代码如下: #include <stdio.h> int main() { printf(“Hello, world.\n”); return 0; } 通常我们使用gcc来生成可执行程序,命令为:gcc hello.c,默认生成可执行文件a.out 其实编译(包括链接)的命令:g
程序员互动联盟
2018/03/16
11K0
【C语言系列】C语言编译流程分析
转载:【AI系统】GCC 主要特征
GCC(GNU Compiler Collection,GNU 编译器集合)最初是作为 GNU 操作系统的编译器编写的,旨在为 GNU/Linux 系统开发一个高效的 C 编译器。其历史可以追溯到 1987 年,当时由理查德·斯托曼(Richard Stallman)创建,作为 GNU 课程的一部分。
聊月夜以予星辰
2024/12/11
920
转载:【AI系统】GCC 主要特征
【Linux】Linux环境基础开发工具
这个工具用于 windows 机器和远端的 Linux 机器通过 XShell 传输文件 .
用户11290673
2025/05/09
1000
【Linux】Linux环境基础开发工具
【Linux】深度解析与实战应用:GCC/G++编译器入门指南
  在Linux系统中,GCC(GNU Compiler Collection)是极其重要且广泛使用的编译器,它支持多种编程语言,包括C、C++、Objective-C、Java、Fortran等。GCC以其高效、灵活和跨平台的特点赢得了开发者的青睐。本文将详细介绍GCC中的C编译器gcc和C++编译器g++的基本使用方法和编译过程。
大耳朵土土垚
2024/09/25
3560
【Linux】深度解析与实战应用:GCC/G++编译器入门指南
vim编辑器和gcc/g++编辑器的使用讲解
vim是Linux的编写代码的工具,是一种多模式的编辑器。 Linux中vim的常用的模式大概可以分为三种,分别是: 命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode)
ahao
2024/03/24
2840
vim编辑器和gcc/g++编辑器的使用讲解
【Linux】Linux开发工具-vim / 编译器-gcc/g++ / 调试器-gdb / git操作 / 项目自动化构建工具-make/Makefile
我们在Windows中有很多的编译环境,大家应该都很熟悉,但是在Linux中,我们怎么写代码呢?
用户10925563
2024/06/04
1420
【Linux】Linux开发工具-vim / 编译器-gcc/g++ / 调试器-gdb / git操作 / 项目自动化构建工具-make/Makefile
【AI系统】GCC 主要特征
GCC(GNU Compiler Collection,GNU 编译器集合)最初是作为 GNU 操作系统的编译器编写的,旨在为 GNU/Linux 系统开发一个高效的 C 编译器。其历史可以追溯到 1987 年,当时由理查德·斯托曼(Richard Stallman)创建,作为 GNU 课程的一部分。
用户11307734
2024/11/27
1160
Linux下动态库(.so)和静态库(.a) 的区别
动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。
bear_fish
2018/09/20
17.6K0
用gcc编译c语言程序以及其编译过程
对于初学c语言编程的我们来说,学会如何使用gcc编译器工具,对理解c语言的执行过程,加深对c语言的理解很重要!!!
黑泽君
2018/10/11
1.7K0
【C++】使用g++指令控制【翻译】各个过程
YY的秘密代码小屋
2024/02/05
1990
【C++】使用g++指令控制【翻译】各个过程
深入理解GCC 和 G++ 编译器
GCC(GNU Compiler Collection)和 G++ 是 GNU 项目的一部分。GCC 是一个多语言支持的编译器,可以处理 C、C++、Fortran 等语言,而 G++ 是 GCC 的 C++ 前端,用于专门处理 C++ 源代码。
DevKevin
2024/12/31
3580
库的概念:动态库与静态库
库是一组封装好的函数或方法,它们可以被多个程序复用,从而避免重复编写相同功能的代码。例如,标准的数学函数库、字符串操作库都属于常用的库。
DevKevin
2025/01/03
3620
【linux学习指南】Linux编译器 gcc和g++使用
预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E hello.c –o hello.i 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
学习起来吧
2024/09/11
4110
【linux学习指南】Linux编译器 gcc和g++使用
GCC写个库给你玩,就这?
「静态库(.a)」:程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。静态库比较占用磁盘空间,而且程序不可以共享静态库。运行时也是比较占内存的,因为每个程序都包含了一份静态库。
DeROy
2021/01/05
1.1K0
Linux交叉编译Windows静态库
静态库是一个包含预编译代码的文件,可以与可执行程序链接以创建单个自包含的可执行文件。静态库中的代码直接链接到可执行文件中,这使得它比动态库更快、更高效。
Linux兵工厂
2024/04/15
6130
Linux交叉编译Windows静态库
Linux gcc编译生成静态库和共享动态库的过程
这篇文章主要通过实例演示在Linux下如何使用gcc分别编译生成静态库和动态库文件以及其它程序如何使用这个生成的静态库和动态库。
typecodes
2024/03/29
9080
Linux gcc编译生成静态库和共享动态库的过程
【Linux探索学习】第八弹——Linux工具篇(三):Linux 中的编译器 GCC 的编译原理和使用详解
Linux下的vim编辑器:【Linux探索学习】第七弹——Linux的工具(二):Linux下vim编辑器的使用详解-CSDN博客
GG Bond1
2024/10/25
2560
【Linux探索学习】第八弹——Linux工具篇(三):Linux 中的编译器 GCC 的编译原理和使用详解
程序生成之编译、链接、加载浅析
剑影啸清寒
2018/01/02
1.3K0
程序生成之编译、链接、加载浅析
编译器gcc/g++ --【Linux基础开发工具】
• 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后, gcc 把代码翻译成汇编语言。
小志biubiu
2025/02/27
3740
推荐阅读
相关推荐
Linux编译工具:gcc入门
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验