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. tSNE算法在自然语言处理中的应用:文本降维和可视化

    目录 技术原理及概念 t-SNE(Toeplitz-Stochastic Neural Network)是一种常用的文本降维和可视化算法,它的核心思想是将高维文本数据映射到低维空间,同时保持数据的一致 ...

  2. 【linux命令】最强大的编辑器vim用法简介(基础篇)

    vim编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器.它主要分为命令令行模式.插入模式和底行模式这三种,下面主要介绍一下这三种模式最简单常用的用法. 一.命令 ...

  3. React学习时,outlet 路由配置 (prop传参处理,跳转的实现,父子数据共享)

    index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App' ...

  4. 解密Prompt系列10. 思维链COT原理探究

    前一章思维链基础和进阶玩法我们介绍了如何写Chain-of-thought Prompt来激活生成逐步推理,并提高模型解决复杂问题的能力,这一章我们追本溯源,讨论下COT的哪些元素是提升模型表现的核心 ...

  5. 聊天室(二)__ unipush 推送实现详细教程

    一.推送作用 推送作用我就不废话了,能做推送的都知道作用,直接上干货. 二.unipush 快速开通   Dcloud 开发者实名认证注册账号,绑定对应的 app 信息. uni-push产品有2个入 ...

  6. smarty 拼接字符串

    smarty 拼接字符串 newstr = [oldstr]|cat:[appendstr] 1 {$name = "Tom"} 2 {$phone = "1381234 ...

  7. 体细胞突变检测分析流程-系列1( WES&Panel)

    Sentieon●体细胞变异检测-系列1   Sentieon 致力于解决生物信息数据分析中的速度与准确度瓶颈,通过算法的深度优化和企业级的软件工程,大幅度提升NGS数据处理的效率.准确度和可靠性. ...

  8. 2023河南省ICPC大学生程序设计竞赛-wh

    第一次出去比赛,首先感谢程老师选择我们新生更多的比赛机会,感谢! 在周六我们一起做了高铁出发取洛阳参加icpc河南省赛,不得不说洛阳师范学院确实环境很好看..在热身赛时,已经被泼了冷水,这C也太难了, ...

  9. Nginx获取用户真实IP

    Nginx获取用户真实IP地址 本人在一次项目中,使用Nginx需要获取到用户IP,本来可以很常规的获取的,可现实往往不常规,项目是前后端分离的,部署时,前端使用了Nginx进行了代理并转发,后端也使 ...

  10. RocketMq消费原理及源码解析

    消费原理概览 先简单说下常见的rocketMq的部署方式,上图中broker为真正计算和存储消息的地方,而nameServer负责维护broker地 图中右侧consume message部分即是本文 ...