linux下c程序的链接、装载和库(3)

9. 目标文件放在一起-->静态库。

你的同事给出的目标文件太多了,从 one.o two.o …… …… 一直到 xxx.o。

好的,你如果真正想用,你的同事提供的这些现有的目标文件,你得做三件事:

一,查看自己的源文件,看看用到了哪些函数;

二,明确这些函数来自于哪个目标文件,本例中,很容易,因为函数的名字和目标文件的名字是对应的,比如one.o就会提供一个名称为one的函数;

三,使用 ld ,将你自己的目标文件和第二步中找到的那些目标文件链接起来,生成可执行文件。

第一步就是个很耗时的过程;

第二步其实也不简单,因为,你根本不能假设,函数的名字和目标文件的名字是对应的,本文只是举一个例子而已;

第三步嘛,也很麻烦,因为你要手动输入这些目标文件的名字,万一打错字怎么办?

所以,你的同事,将 one.o two.o …… …… 一直到 xxx.o 统一制作成一个文件,叫做 goodThings.a,这个 goodThings.a 就包含了所有的目标文件了。

你使用的时候,只需要这么做,假设你自己的目标文件叫做 main.o,

ld main.o goodThings.a -o go

简洁明了!一步成功! ld 这个命令会自动在 goodThings.a 中去查找 main.o 使用的目标文件,并链接起来。

好,正式介绍 goodThings.a 这个新“人物”。

这个东西就是静态库。(关于静态这个词,后面再讲)

说白了,就是目标文件的打包,放在一块而已。

ar 这个命令可以用来制作静态库:

ar -r goodThings.a one.o two.o three.o ………… xxx.o

这样就能把 one.o 一直到 xxx.o 放在 goodThings.a 里了。

你可以查看一个静态库文件里有哪些目标文件:

ar -t goodThings.a

不过,建议将静态库的名字叫成 libxxx.a 这样的格式,这样更符合命名规范,实际上是,这样的命名规范是有好处的。因为可以这样用:

ld main.o -L . -lxxx -o go

ld 会在本目录下去找 libxxx.a。当然,这里假设,你把 libxxx.a 放在本目录了。其中 -L . 就是说,在本目录下去找的意思。

10. 静态到动态。

前面说到了装载的概念,就是把程序从硬盘搬到内存去,从而开始执行。

可以简单的说:

静态:链接过程在装载之前已经完成。

动态:等到装载的时候再去找相应的库文件,进而链接。

关于静态,一劳永逸,所有的东西都在这里了,想什么时候执行就什么时候执行。

动态呢,不是这样,执行的时候,去找我需要什么,再链接,再装载。

讨论一下动态的好处。

举一个例子,看电视。

小明和小强都要看电视,于是他们一人背着一个电视,似乎,有点累。

小明说,把电视放到房间里吧,嗯,于是,他俩在一个房间里,打开两个电视,都在看一个台,似乎,有点浪费。

小明说,既然看一个台,那关一台,似乎,这样很好。

假如小明和小强同时用到了 one.o ,那么可以推出一个结果,小明和小强的 可执行文件里,一定都包含这个 one.o。

第一,浪费硬盘空间;(两份可执行文件都包含了 one.o )

第二,程序装载时,浪费内存。(因为 one.o 被装载了两次)

动态库,就可以解决以上两个问题。

同样的代码,硬盘上应该可以只存在一份,内存中也应该只存在一份,以达到节省的效果。

这就是为什么,动态链接,是在程序被装载的时候,才去链接。(因为早链接了,不就占硬盘空间了么)

这就是为什么,动态链接,可以节省内存。(因为相同的库,我只链接一次,放在内存里,第二份可执行文件依然可以共享这个库)

时间: 2024-10-22 11:38:57

linux下c程序的链接、装载和库(3)的相关文章

Linux下C程序的链接过程

今天看到一个很有意思的小程序,它让我对Linux下C程序的编译链接有了一个全新的认识! 这个程序的就是写一个简单的输出"hello World!":   要求:1.不使用C运行库,写一个独立于任何库的程序.(也就是说我们不能#include<stdio>).       2.不适用main函数为程序的入口(大家都知道一般使用了库的程序都是使用main函数作为程序的入口,在这里我们使用自己写的函数nomain作为程序的入口).       3.使用连接器ld把程序的所有段合为

linux下c程序的链接、装载和库(1)

读完<程序员的自我修养--链接.装载和库>相关章节,想来总结一下,若有错误,请指正,多谢. 1. 什么叫目标文件? 你的工程里有很多xxx.c这样的源文件,这些文件是文本文件,只有人能够认识(当然编译器认识),但是,cpu可不认识.问题就是,真正执行指令的是cpu. 让编译器翻译一下(这里面有很多过程,这不是这篇文章的重点),一般来说,一个xxx.c文件就能翻译成一个xxx.o,这就是目标文件了. 一个源文件就对应一个目标文件,这个目标文件就存储了有关这个源文件的所有信息了,包括在这个源文件里

linux下c程序的链接、装载和库(2)

5. 重定义错误. 一个最终的可执行文件里,绝对不允许出现两个同名的全局变量,也不允许出现同名的全局函数. 全局函数:只要不用 static 修饰符修饰的函数,全部都是全局的. 全局变量:函数外声明定义,且不加 static 修饰符修饰的变量. 例如,one.c 里有一个函数 function, 那么你如果想让 main.c 生成的 main.o 能够链接 one.o 的话,那么 main.c 里就不能再有一个函数叫做 function 了.否则就会报重定义错误. 这就好像,你的班上有两个人都叫

Linux下软链接与硬链接的区别

Linux下软链接与硬链接的区别 Linux中的文件都文件名和数据,在linux上面被分为两个部分:元数据与数据.用户数据,即文件数据块(data block),数据块是记录文件真实内容的地方,而元数据是文件的附加属性,如大小,创建时间,所有者等信息.在Linux中,元数据中的inode号(inode是文件的元数据的一部分,但其不包含文件名,inode号即索引节点号)才是文件的唯一标识而不是文件名.文件名仅是为了方便人们的记忆和使用,系统或程序通过inode号寻找正确的文件数据快.下图为程序通过

Linux下的程序包管理之源码形式

 Linux下程序包管理之源码形式 程序包的前世今生: 说到程序包管理,不得不提到是就是程序包是由什么组成的?也就是怎么形成的?程序是由源代码程序经过预处理.编译.然后汇编形成二进制的程序,这是针对特定硬件而形成的程序.有计算机编程基础的同学都应该知道源代码编译的时候是要调用特定的库(库文件),而这些库,在不同的系统上是不同的,比如Linux和window上的就不同,不同发行版的Linux上的库也不尽相同,所以这就导致了在不同种类系统上编译生成的二进制程序的运行环境也不尽相同,那么这些程序是不能

Linux下c++程序内存泄漏检测代码范例

Linux下对于程序内存泄漏检测的方法很多,最常用的的莫过于使用valgrind工具.但是valgrind相当于让程序在虚拟机中运行,会带来较大的系统资源开销,还会对程序的运行效率产生较大影响,对于那种资源占用大的程序,如果需要长时间运行才能暴露的泄漏问题,它就显得不太好用. linux下的c++程序中自己实现一个轻量级的泄漏检测代码其实是比较方便的,下面我就给出一个简单的范例,并作简单的说明.当然,我们还是应该提倡使用共享指针,用共享指针自动管理内存可以避免内存泄漏这样的不必要的麻烦. 基本原

windows下QT前台和linux下后台程序通过socket通信

通常情况下,linux下的后台程序不需要GUI进行展示,而前台程序往往有个界面,方便和用户的交互.本文所演示的例 子,是QT 程序和后台linux进程(C语言)交互,通过socket传输的内容是结构体.因为QT本身是跨平台的框架,因此以后前端程序移植到其它平台依然能很好 的运行. 结构体的定义如下: struct Test              {                      int a;                      char b;              };

linux下java程序与C语言程序通过SOCKET通信的简单例子

linux下java程序与C语言程序通过SOCKET通信的简单例子 今天上午实验了java程序与c语言程序通过socket进行通信.由于没学过java,因此只是编写了C语言端的代码,java端的代码是从网上别的文章中找的,经过少量修改后与C语言端程序通信成功. 本例中C语言端作为服务器,java端作为客户端 代码如下: /****************** server program *****************/ #include <stdio.h> #include <sy

[转帖]Linux 下软链接和硬链接的区别

Linux 下软链接和硬链接的区别 http://os.51cto.com/art/201911/605267.htm 软连接 文件是小的 只是一个链接 删除和其他处理不影响 原始文件的计数 删除源文件 链接文件立马完蛋 但是可以跨文件挂载点进行连接. 硬链接 增加了innode 的引用计数. 删除时 只要还有一个有链接 文件就还有. 但是不能跨挂载点进行硬链接 软连接 就是 ln -s 硬链接 直接 ln 在 Linux 系统中,一切都是文件,然而为了区分不同类型的事物,我们有了: 普通文件