C语言学习笔记_函数与函数库
函数库
函数是模块化的,因此可以被复用。
函数库就是一些事先写好的函数的集合。
函数库的提供形式:动态链接库和静态链接库:
静态链接库
静态库是商业公司将自己的函数库源码经过只编译不链接形成的.o的目标文件;
然后用ar工具将.o文件归档成.a的归档文件(.a的归档文件又被称为静态链接库文件);
商业公司通过发布.a库文件和.h头文件来提供静态库给客户使用;
客户拿到,a和.h文件后,通过头文件中拿出被调用的那个函数的编译后的.o二进制代码链接进去形成最终的可执行程序;
静态链接通过将库中的代码链接进当前程序,优点是不依赖环境,在哪里都能运行,缺点是程序将会非常大(因为库函数也被链接进了程序中);
动态链接库
动态链接库比静态出现的晚;
gcc编译器默认使用动态链接,需要使用-static来强制静态链接;
动态链接并不将库中的代码链接进程序,只是做一个标记,当运行的时候再去加载。 优点是程序体积小占用内存小,缺点是程序依赖环境,在库文件不存在时无法运行;
有多个应用程序都使用了库函数时,动态链接库就会很有优势,因为这样内存中的库函数只有一份,不会重复加载;
字符串处理函数
// TODO
数学库函数
数学运算的函数定义在:/usr/include/i386-linux-gnu/bits/mathcalls.h
开平方函数:double sqrt(double x);
注意,需要在编译时明确给出需要扩展的库的名字,这是因为库函数太多,连接器在库函数中搜索的时间会很长,为了提升链接速度,链接器只会去寻找几个最常用的库,所以不常用的库被调用的时候需要给出扩展库的名字;
连接时使用 -lxxx指示链接器去libxxx.so中搜索,本例中数学库函数需要添加 -lm,表示链接到libm.so中;
制作静态链接库
静态链接库的后缀名是.a;
第一步,编写源文件和头文件,假设命名为sp.c和sp.h;
第二步,编写makefile文件,makefile如下:
all:
gcc sp.c -o sp.o -c
ar -rc libsp.a sp.o
第一句的意思是只编译不链接,创建出sp.o,第二局的意思是利用ar命令将sp.o归档在libsp.a文件中;
第三步,编写test文件测试此库函数文件是否有效,makefile文件如下:
all:
gcc test.c -o test -lsp -L.
其中,-lsp表示指定库函数为sp,-L.表示指定库函数的路径为当前路径(”.“表示当前路径);
最后nm命令可以检查归档文件.a中有哪些.o文件,分别有什么函数;
制作动态链接库
动态链接库的后缀名为.so,对应于windwos下是dll;
第一步,编写源文件和头文件,假设命名为sp.c和sp.h;
第二步,编写makefile文件如下:
all:
gcc sp.c -o sp.o -c -fPIC
gcc -o libsp.so sp.o -shared
-fPIC是位置无关码,-shared表示以共享库的方式来链接;
第三步,编写test文件测试此库函数是否有效,
all:
gcc test.c -o test -lsp -L.
由于动态链接库并没有真正的链接源函数,所以此时运行并不能成功,需要第四步:
第四步,将libsp.so放到系统的固定目录下:/usr/lib目录;由于此目录一般放重要的库函数,所以不推荐此方法,可以考虑第五步的环境变量;
第五步,使用环境变量LD_LIBRARY_PATH,操作系统在加载固定目录/usr/lib之前,会去LD_LIBRARY_PATH这个环境变量所指定的目录下去寻找,如果找到就不用去固定目录下找了,否则再去固定目录/usr/lib中;
因此可以将制作的动态链接库所在目录添加进环境变量:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/sky/usr/lib
此时即可运行;
ldd命令
此命令的作用是在一个使用了共享库的程序执行之前解析出这个程序使用了哪些共享库,并查看这些共享库是否能被找到;