Linux中的动态函数库和静态函数库的比较

库函数既提高了代码的利用率,又屏蔽了函数内部实现的细节,给不同开发者提供了统一的接口。从实现来看,库函数可以分为动态函数库和静态函数库。同一组函数,可以根据需要封装成静态库和动态库。那么生成静态库和动态库有什么区别?静态库和动态库对函数的实现上各有些什么要求?两者对内存各有什么影响呢?下面就带着这些问题一起开探讨。

静态库和动态库生成方式的区别
为了简化,下面以一个只有一个函数的库的实现来说明。库函数的代码demo.c如下:
/*******************************************************************/
int cal(int a, int b)
{
        return (a^(a << b)) + (b << a);
}

main.c中的代码如下:
[[email protected] mylib]# cat main.c
#include<stdio.h>
#include "demo.h"

int main(void)
{
        printf("Call cal(7,8) = %08x\n", cal(7,8));
}
[[email protected] mylib]# cat demo.h
int cal(int, int);
如果需要生成动态库,则需要用到下面的Makefile:
MYLIB := libdemo.so
BIN := test
CFLAG := -Wall -I../ -I./ -DTEST=1
LIBFLAG := -L./ -rpath=/home/xqch/workspace/mylib ./ -ldemo

all: $(MYLIB) $(BIN)

$(BIN): main.o
        gcc $(CFLAG) -L/home/xqch/workspace/mylib -ldemo -o [email protected]  $^

$(MYLIB): demo.o
        ld -shared -fpic -rpath=/home/xqch/workspace/mylib -o [email protected] $^

%.o:%.c
        gcc $(CFLAG) -c -o [email protected] $<

.PHONY: install clean

install:
        cp $(MYLIB) /usr/lib
        cp $(MYLIB) /lib

clean:
        rm -rf *.o $(BIN) $(MYLIB)
而生成静态库的过程如下:
[[email protected] mylib]$ cat Makefile
MYLIB := libdemo.a
BIN := main
CFLAG := -Wall -I../ -I./ -DTEST

all: $(MYLIB) $(BIN)

$(BIN): main.o
        gcc $(CFLAG) -o [email protected]  $^ $(MYLIB)

$(MYLIB): demo.o
        ar -rcv [email protected] $^

%.o:%.c
        gcc $(CFLAG) -c -o [email protected] $<

.PHONY: clean
clean:
        rm -rf *.o $(BIN) $(MYLIB)

静态库和动态库生成的二进制代码的区别
基于上面的两个Makefile我们可以对比下它们的区别:
[[email protected] mylib]$ ls -alrt main
-rwxrwxr-x. 1 xqch xqch 7696 Oct 26 21:21 main
dynamic:
[[email protected] mylib]$ ls -alrt test
-rwxrwxr-x. 1 xqch xqch 7602 Oct 25 19:32 test
可以看到静态库生成的可执行文件比需要链接动态库生成的可执行文件大.通过反汇编,我们可以看到差异就在于对库函数的调用方式不同:
static:
08048724 <cal>:
 8048724:   55                      push   %ebp
 8048725:   89 e5                   mov    %esp,%ebp                                                                                                  
 8048727:   53                      push   %ebx
 8048728:   83 ec 04                sub    $0x4,%esp
 804872b:   a1 30 a0 04 08          mov    0x804a030,%eax
 8048730:   83 c0 01                add    $0x1,%eax
 8048733:   a3 30 a0 04 08          mov    %eax,0x804a030
 8048738:   a1 3c a0 04 08          mov    0x804a03c,%eax
 804873d:   83 c0 01                add    $0x1,%eax
 8048740:   a3 3c a0 04 08          mov    %eax,0x804a03c
 8048745:   a1 38 a0 04 08          mov    0x804a038,%eax
 804874a:   83 c0 01                add    $0x1,%eax
 804874d:   a3 38 a0 04 08          mov    %eax,0x804a038
 8048752:   8b 0d 38 a0 04 08       mov    0x804a038,%ecx

dynamic:
080485a0 <[email protected]>:                                                                                                                                                    
 80485a0:   ff 25 2c a0 04 08       jmp    *0x804a02c
 80485a6:   68 40 00 00 00          push   $0x40
 80485ab:   e9 60 ff ff ff          jmp    8048510 <_init+0x2c>

静态库和动态库对代码的要求
两者共同点是如果需要对多线程代码的支持,代码里不能出现全局变量和动态变量和静态变量(函数内部和外部的),因为它们最后都是放在.bss或者.data段,而同进程的不同线程间共享同一个数据段,某个线程调用使用那些变量函数后,后面的调用函数看到就是改变的值。

静态库和动态库对内存的影响
静态程序占用内存较多,动态程序反之。因为动态程序是在执行时连接,添加被调用的动态函数的地址到.got.plt(process link table)中去。

时间: 2024-08-25 09:43:06

Linux中的动态函数库和静态函数库的比较的相关文章

C语言的动态函数库和静态函数库的生成和使用(linux环境下)

软件开发往往是一个十分庞大的工程.需要消耗大量的脑力.借助别人已经开发好的库,往往能提高效率,下面将介绍如何开发和使用共享的库文件.使用别人已经开发好的库,就像是我们想要建造一辆汽车十分困难,但是如果汽车的各大部件都已经存在并且可以获得,我们要做的工作就是组装,组装过程一定比设计这些部件要轻松. 函数库分为两种静态(static)函数库和动态(shared)函数库.两者都是函数的集合.区别:在编译的时候会把静态函数库的内容加到目标程序中,目标程序具有函数库的代码;而动态函数库是在执行的时候才把函

linux 中使用动态.so库步骤以及注意

在linux工程中添加libtest.so动态库 1.添加该动态库相应的头文件 2.添加动态链接库的路径(可以将动态库放在/usr/lib/下,也可以使用绝对路径) 3.在makefile中添加动态库的链接(-ltest) 注: 上述步骤添加完成后编译如果还出现找不到函数的情况可能是c文件不能在c++被调用,在库的头文件中添加 #ifdef _cplusplus extern "C"{ #endif n个函数描述 #ifdef _cplusplus } #endif

Linux中的fork()函数

 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程, 也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都 复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. 我们来看一个例子: /* *  fork_test.c *  version 1

Linux中的动态库(共享库)的制作

一.整体大纲 二.共享库的制作 1. 命名规则: lib + 名字 + .so 2. 制作步骤: 1) 生成与位置无关的代码 (生成与位置无关的.o)    2) 将.o打包成共享库(动态库) 3. 发布和使用共享库: 4. 解决程序执行时动态库无法被加载的问题: 1)放到系统的库目录 中 -- 不允许使用 2)临时测试 环境变量: LD_LIBRARY_PATH=将动态库的路径设置给该变量          将设置的值, 导入到系统环境变量中: export LD_LIBRARY_PATH 

练习一下linux中的list函数。

所有的list函数见 include/linux/list.h 自己从 include/linux/list.h 拷贝了一些函数到自己的list.c中, 然后练习了一下. 没有别的目的,就是想熟练一下.毕竟linux内核代码中试用了大量的list函数. list的函数太方便使用了. 文件:list.c 1 #include <stdio.h> 2 // #include <linux/list.h> 3 4 struct list_head { 5 struct list_head

linux中内核延时函数

第一类延时函数原型是:(忙等) void ndelay(unsigned long nsecs); void udelay(unsigned long usecs); void mdelay(unsigned long msecs); 说明:内核函数 ndelay, udelay, 以及 mdelay 对于短延时好用, 分别延后执行指定的纳秒数, 微秒数或者毫秒数. 它们涉及到的延时常常是最多几个毫秒. 第二类延时函数原型是:(使进程进入休眠) void msleep(unsigned int

Linux中的入口函数main

main()函数,想必大家都不陌生了,从刚开始写程序的时候,大家便开始写main(),我们都知道main是程序的入口.那main作为一个函数,又是谁调用的它,它是怎么被调用的,返回给谁,返回的又是什么?这次我们来探讨一下这个问题. 1. main()函数的形式先来说说main函数的定义,较早开始写C程序的肯定都用过这样的定义void main(){},其实翻翻C/C++标准,从来没有定义过void main().在C标准中main的定义只有两种:        int main(void)   

linux中字符串转换函数 simple_strtoul

Linux内核中提供的一些字符串转换函数: lib/vsprintf.c [html] view plain copy print? 1. unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) 2. unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) 3. long simple_st

Linux中backtrace()系列函数的应用实例

一.引言 backtrace()系列函数可用来输出代码出错时的函数调用关系. A backtrace is the series of currently active function calls for the program. #include <execinfo.h> int backtrace(void **buffer, int size); char **backtrace_symbols(void *const *buffer, int size); void backtrac