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

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

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

int main(void)
{
        printf("Call cal(7,8) = %08x\n", cal(7,8));
}
[root@localhost 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 $@  $^

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

%.o:%.c
        gcc $(CFLAG) -c -o $@ $<

.PHONY: ×××tall clean

×××tall:
        cp $(MYLIB) /usr/lib
        cp $(MYLIB) /lib

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

all: $(MYLIB) $(BIN)

$(BIN): main.o
        gcc $(CFLAG) -o $@  $^ $(MYLIB)

$(MYLIB): demo.o
        ar -rcv $@ $^

%.o:%.c
        gcc $(CFLAG) -c -o $@ $<


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

静态库和动态库生成的二进制代码的区别
基于上面的两个Makefile我们可以对比下它们的区别:
[xqch@localhost mylib]$ ls -alrt main
-rwxrwxr-x. 1 xqch xqch 7696 Oct 26 21:21 main
dynamic:
[xqch@localhost 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 <cal@plt>:                                                                                                                                                    
 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)中去。