头文件和库文件区别,动态库和静态库的区别,动静态库的生成

一、什么是头文件?什么是库文件?有什么区别?

先说总结

头文件是包含函数声明,宏定义,类的声明的文件。

在linux中一般头文件会在/usr/include中,如果没有可以使用 locate命令查找文件所在位置。

库文件是一种目标文件,静态库是可重定位目标文件,动态库是共享目标文件。(后面有解释)

一般在/usr/lib、/usr/lib64、/lib、/lib64都包含库文件

头文件是在预处理时使用;库文件是链接时使用。

头文件内容还是高级语言内容;库文件是二进制文件。

目标文件

在解释静态库和动态库之前,需要简单了解一下什么是目标文件。目标文件常常按照特定格式来组织,在linux下,它是ELF格式(Executable Linkable Format,可执行可链接格式),而在windows下是PE(Portable Executable,可移植可执行)。

而通常目标文件有三种形式:

  • 可执行目标文件。即我们通常所认识的,可直接运行的二进制文件。

  • 可重定位目标文件。包含了二进制的代码和数据,可以与其他可重定位目标文件合并,并创建一个可执行目标文件。

  • 共享目标文件。它是一种在加载或者运行时进行链接的特殊可重定位目标文件。

    使用readelf -a filename 可以查看目标文件的ELF格式

二、什么是静态库?什么是动态库?有什么区别?

静态库在linux中是以.a(archive)为后缀,作用是在进行链接生成可执行文件时,从静态库文件中拷贝需要的内容到最终的可执行文件中。

//在使用gcc编译时采用 -static选项来进行静态文件的链接:

gcc -c main.c

gcc -static -o main main.o

动态库在linux中是以.so(shared object)为后缀,它并不在链接时将需要的二进制代码都拷贝到可执行文件中,而是拷贝一些重定位和符号表信息,当程序运行时需要的时候再通过符号表从动态库中获取。

//使用gcc编译默认采用动态链接

gcc -o main main.c

三、为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明的函数呢?

首先要熟悉程序编译过程

预处理->编译->汇编->链接

  • 预处理(preprocessing)的时候把头文件内容包含进来。

gcc -E -o main.i main.c

  • 编译,但不包括汇编(compilation, do not assemble)将预处理后的文件转换成汇编代码。

gcc -S -o main.S main.i

  • 汇编将编译后的程序转换为二进制文件,也就是可重定向目标文件。

gcc -c -o main.o main.S

  • 链接将具体的动态库或者静态库中的代码(也就是包的头文件中的代码实现部分)拷贝代码或拷贝符号表的方式,生成可执行目标文件。

gcc -o main main.o

动静态库区别

1.可执行文件大小不一样

静态链接的可执行文件要比动态链接的可执行文件大得多,因为它将需要用到的代码从二进制文件中拷贝了一份,而动态链接仅仅是复制了一些重定位和符号表信息。

2.占用磁盘大小不一样

如果有多个可执行文件,那么静态库中的同一个函数的代码就会被复制多次,而动态库只有一份,因此使用静态库占用的磁盘空间相对比动态库要大。

3.拓展性与兼容性不一样

如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。

4.依赖不一样

静态连接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。

即便如此,系统中一般存在一些大量公用的库,所以使用动态库并不会有什么问题。

5.复杂性不一样

相对来说,动态库的处理要比静态库要复杂,例如如何在运行时确认地址?多个进程如何共享一个动态库?当然,作为调用者我们不需要关注,另外动态库版本的管理也是一项技术活。这也不在本文的讨论范围。

6.加载速度不一样

由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性是值得的。再加上局部性原理,牺牲的性能并不多。(局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。)

四、如何生成动静态库文件

静态库的生成

//1.先写出相应的.h文件和对应的.c文件

//2.编译.c文件

//3.使用ar工具将.o文件归档生成.a静态库文件

[root@localhost linux]# ls
add.c add.h main.c sub.c sub.h
[root@localhost linux]# gcc -c add.c -o add.o
[root@localhost linux]# gcc -c sub.c -o sub.o
生成静态库
[root@localhost linux]# ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)
查看静态库中的目录列表
[root@localhost linux]# ar -tv libmymath.a
rw-r–r-- 0/0 1240 Sep 15 16:53 2017 add.o
rw-r–r-- 0/0 1240 Sep 15 16:53 2017 sub.o
t:列出静态库中的文件
v:verbose 详细信息
[root@localhost linux]# gcc main.c -L. -lmymath
-L 指定库路径
-l 指定库名
测试目标文件生成后,静态库删掉,程序照样可以运行。

注意:静态库文件和动态库文件的命名规则是libxxxx.so/libxxxx.a,在进行 链接时只用lxxxx即可

库文件的搜索路径

  • 从左往右搜索-L指定的目录
  • 有环境变量指定的目录(LIBRAY_PATH)
  • 由系统指定的目录
    • /usr/lib
    • /usr/local/lib

动态库的生成

  • shared:表示生成共享库格式
  • fPIC:产生位置无关码(position independent code)

示例:

[root@localhost linux]# gcc -fPIC -c sub.c add.c

[root@localhost linux]# gcc -shared -o libmymath.so *.o

[root@localhost linux]# ls

add.c add.h add.o libmymath.so main.c sub.c sub.h sub.o

总结

静态库和动态库的具体链接方式并没在本文讨论,本文仅仅介绍动静态库的区别和是什么和怎么生成,对于我来说已经足够。更多内容需要读者自行阅读相关书籍。

参考

参考链接

猜你喜欢

转载自blog.csdn.net/weixin_42458272/article/details/106193786