C源程序需要经过预处理、编译、汇编几个阶段,得到各自源文件对应的可重定位目标文件,可重定位目标文件就是各个源文件的二进制机器代码,一般是.o格式。比如:util1.c、util2.c及main.c三个C源文件,经过预处理器、编译器、汇编器的处理,就可以得到各自的目标文件util1.o,util2.o以及main.o。可重定位目标文件中的地址是从0开始的,需要链接器将若干个可重定位目标文件通过符号解析重定位等工作,链接成为一个可执行的二进制目标文件。在Linux下,可以使用gcc -c 对源文件进行预处理、编译、汇编,得到目标文件:

可以看到源文件util1.c及util2.c被编译成为了对应的目标文件util1.o及util2.o。在给定的例子中,util1.c和util2.c实际上分别定义的两个函数add和mult,返回两个整数的加法和乘法结果(这么做有点儿蠢,这里只是作为一个例子,讲清楚后面静态库的概念)。两个函数的定义如下:

//util1.c
int add(int a,int b)
{
return a + b;
} //util2.c
int mult(int a,int b)
{
return a * b;
}

util.h中包含了对这两个函数的声明;main.c使用其中的add函数:

#include <stdio.h>
#include "util.h" int main()
{
int a = 5;
int b = 10;
int c = add(a,b);
printf("%d\n",c);
return 0;
}

实际上,所有的编译系统都提供一种机制,将所有相关的目标模块(即目标文件)打包成为一个单独的文件,称为静态库。在Linux中,静态库以一种被称为存档(archive)的文件格式存放在磁盘中。存档文件由后缀.a标识,.a格式的存档文件是一组连接起来的可重定位目标文件的集合,有一个头部用来描述每个成员目标文件的大小和位置。C标准定义了许多静态库,如标准IO操作scanf,printf,字符串操作strcpy等,它们在libc.a库中;一些浮点数学函数如sin,cos等,它们在libm.a库中。

当然,静态库是目标文件的集合,我们也可以将自己定义的函数编译成目标代码,加入静态库中。为了为若干目标文件创建静态库,可以使用ar rcs:

ar rcs 后面紧跟的libutil.a是创建的静态库的名字,通常以lib三个字母开头,后面的util可以自己指定,静态库以.a为后缀。util1.o 及 util2.o 是我们要加入静态库的两个目标文件。这样,就创建了一个静态库文件libutil.a。可以使用ar t来查看静态库文件中包含的目标文件:

接下来,我们在main函数中使用这个库。要在main中使用libutil.a库,需要链接通过编译main.c得到的目标文件main.o和libutil.a:

可以看到,gcc将main.c对应的目标文件与库libutil.a链接起来,得到了可执行文件main。我们执行可执行文件main,得到期望的结果:

注意,main函数中include了头文件util.h,在util.h中对libutil.a中的函数进行了声明。

那么,重点来了,为什么需要引入静态库这种东西呢?将C标准提供的所有库都放在一个可重定位目标模块中不行吗?

事实上是可以的,不过,这种设计有一个很大的缺点是系统中的每个可执行文件都要包含这个整个的大的目标模块的完全副本,这样做很浪费存储空间。比如,C标准的libc.a大约5MB,现在有一台机器装载了15个用到了C标准库的可执行文件,那么这15个可执行文件里每一个实际上都经过链接器的链接,嵌入了libc.a库中的5MB目标代码,而实际上它们可能用到5MB目标代码里的很小一部分(比如,某个目标文件可能只引用了标准库中的strcpy函数),这样,造成了严重的存储空间浪费。而静态库实际上提供了这样一种功能:相关的函数可以被编译为独立的目标模块,然后封装成一个单独的静态库文件,当链接器构造一个可执行文件时,它只“提取”静态库里被应用程序引用的目标模块(换句话说,对于程序中用不到的,链接器不会将它复制到可执行文件中去)。

还有一种方法,就是把每个函数创建独立的可重定位目标文件。这种方法对于应用程序员来说是及其不友好的,因为这种方法要求应用程序员显示地链接需要的目标模块到可执行文件中,这是一个容易出错且耗时的过程。

总结来说,静态库提供了将每一个目标模块独立地打包的功能,并且可以由链接器自动地提取被程序引用的目标模块,这减少了可执行文件在磁盘和内存中的大小,并且大大降低了程序员链接各个目标文件的压力。

C静态库的创建与使用--为什么要引入静态库?的更多相关文章

  1. ios中静态库的创建和使用、制作通用静态库(Cocoa Touch Static Library)

    创建静态库可能出于以下几个理由: 1.你想将工具类代码或者第三方插件快捷的分享给其他人而无需拷贝大量文件.2.你想让一些通用代码处于自己的掌控之下,以便于修复和升级.3.你想将库共享给其他人,但不想让 ...

  2. Qt——动态库的创建和使用

    一.动态库是什么 很多人写程序的人都见过.lib和.dll文件,对动态库也略有耳闻. 生成动态库后可以得到两个文件,后缀名分别是.lib以及.dll. 简而言之,.lib称为导入库,相当于头文件:.d ...

  3. iOS - 静态库的创建与使用

    在日常项目开发中,不论是为了两个公司项目上的业务交流还是为了减少项目的编译时间,有的时候我们会把项目中的私密内容打包成静态库,或者是把项目中变动较少一部分打包成静态库以便提高编译效率,那么下面我们就来 ...

  4. iOS 中 .a 和 .framework 静态库的创建与 .bundle 资源包的使用

    iOS 中 .a 和 .framework 静态库的创建与 .bundle 资源包的使用 前言 开发中经常使用三方库去实现某特定功能,而这些三方库通常又分为开源库和闭源库.开源库可以直接拿到源码,和自 ...

  5. Qt 共享库(动态链接库)和静态链接库的创建及调用

    前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...

  6. Windows下静态库与动态库的创建与使用

    Windows下静态库与动态库的创建与使用 学习内容:本博客介绍了Windows下使用Visual C++ 6.0制作与使用静态库与动态库的方法. --------CONTENTS-------- 一 ...

  7. Qt动态库静态库的创建、使用、多级库依赖、动态库改成静态库等详细说明

    本文描述的是windows系统下,通过qtcreator在pro文件中添加动态库与静态库的方法: 1.添加动态库(直接添加动态库文件.dll,非子项目) 通过qtcreator创建动态库的方法就不在此 ...

  8. windows库的创建和使用:静态库+动态库

    windows库的创建和使用:静态库+动态库   一.静态库的创建和使用 1. 静态库创建 (1)首先创建projecttest,測试代码例如以下: 1) test.h void test_print ...

  9. 使用Xcode 5创建Cocoa Touch Static Library(静态库)

    转自:http://blog.csdn.net/jymn_chen/article/details/21036035 首先科普一下静态库的相关知识: 程序编译一般需经预处理.编译.汇编和链接几个步骤. ...

  10. Windows下静态库、动态库的创建和调用过程

    静态库和动态库的使用包括两个方面,1是使用已有的库(调用过程),2是编写一个库供别人使用(创建过程).这里不讲述过多的原理,只说明如何编写,以及不正确编写时会遇见的问题. //注:本文先从简单到复杂, ...

随机推荐

  1. Linux系统运维之Web服务器Nginx安装

    一.介绍 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.本文先整理web服务器内容. 二.环境及软件版本 操作 ...

  2. Pychrm自定义代码块

    Pycharm -> Perferences (command + ,)

  3. spring cloud微服务搭建配置中心之携程开源框架Apollo

    1.Apollo(阿波罗) Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适 ...

  4. Redis 主从同步原理

    一.什么是主从同步? 主从同步,就是将数据冗余备份,主库(Master)将自己库中的数据,同步给从库(Slave). 从库可以一个,也可以多个,如图所示: 二.为什么需要主从同步? Redis 虽然有 ...

  5. CenOS 安装 mysql 临时密码 处理

    数据库 版本 Server version: 8.0.26 MySQL Community Server - GPL:官网下载的包 wget https://cdn.mysql.com//Downlo ...

  6. 好用工具: windows terminal

    直接在微软商店搜索该软件即可,本文介绍无法使用微软商店的情况. 解题思路 当我们无法下载某个软件时,可直接去Github中寻找该项目,知道该软件资源并下载. 下载地址 https://github.c ...

  7. 探究eFuse:硬件保障与系统安全的核心

    探究eFuse:硬件保障与系统安全的核心 图1: 编程熔断的 eFuse eFUSE的全名是"Electrically Programmable Read-Only Memory Fuse& ...

  8. 【解惑】介绍三大数据库的with语句的写法及使用场景

    WITH 子句通常被称为 "Common Table Expressions"(CTE),俗称内存临时表,当使用 WITH 语句时,应注意具体的数据库版本和支持情况.以下是对 My ...

  9. Trino418版本动态加载catalog不需要重启集群修改思路及实现

          熟悉Trino 的同学应该都知道Trino新增.删除 catalog 都需要重启集群,这个生产环境里如果需要频繁增加数据源的场景是非常不友好的操作.     网上关于动态加载Catalog ...

  10. Linux 内核设备树时钟绑定

    这种绑定依然处于开发中,并且基于 benh[1] 的一些实验性工作. 时钟信号源可以由设备树中的任何节点表示.这些节点被指定为时钟提供者.时钟消费者节点使用 phandle 和时钟指示符对将时钟提供者 ...