C标准库函数
学习计划 Unix-C

编译器&链接器

simplyzhao posted @ 2009年2月25日 06:33 in Unix-C Programming , 2394 阅读

头文件
用C语言及其他语言进行程序设计时,我们要用头文件来提供对常量的定义和对系统及库函数调用的声明。
对C语言来说,这些头文件几乎总是在/usr/include目录及其子目录下。
调用C语言编译器时,我们可以使用-I标志来包含保存在子目录或非标准位置的include文件, 例如:
      gcc -I/usr/openwin/include fred.c
它指示编译器不仅在标准位置,也在/usr/openwin/include目录中查找程序fred.c中包含的头文件。

另外,用grep命令来搜索包含某些特定定义和函数原型的头文件是很方便的,例如:

查找包含EXIT_的定义的头文件

grep EXIT_ *.h

 

库文件
库是一组预先编译好的函数的集合,这些函数都是按照可重用的原则编写的,他们通常由一组相互关联的函数组成并执行某项常见的任务。
标准系统库文件一般存储在/lib和/usr/lib目录中。C语言编译器(更确切地说,是链接程序)需要知道要搜索哪些库文件,默认情况下,它只搜索标准C语言库。
库文件的名字总是以lib开头,随后的部分指名这是哪种库(例如,c代表C语言库,m代表数学库)。文件名的最后部分以.开始,然后给出库文件的类型:
  .a   代表传统的静态函数库
  .so  代表共享函数库
我们可以通过给出完整的路径名或用-l标志来指示编译器要搜索的库文件,例如:
  gcc -o fred fred.c /usr/lib/libm.a
这条命令指示编译器编译文件fred.c,将编译产生的程序文件命名为fred,并且除搜索标准的C语言函数库外,还搜索数学库以解决函数引用问题,下面的命令也能产生类似的结果:
  gcc -o fred fred.c -lm
-lm是简写形式,它代表的是标准库目录(/usr/lib)中名为libm.a的函数库。-lm标志的另一个好处是如果有共享库,编译器会自动选择共享库。
另外,我们也可以通过-L标志为编译器增加库的搜索路径。例如:
  gcc -o x11fred -L/usr/openwin/lib x11fred.c -lX11
这条命令用/usr/openwin/lib目录中的libX11库版本来编译和链接程序x11fred.c

当程序需要使用函数库中的某个函数时,它包含一个声明该函数的头文件,编译器和链接器负责将程序代码和函数库结合在一起以组成一个单独的可执行文件。

静态库
也称作归档文件(archive)。
我们可以容易的创建和维护自己的静态库,只要使用ar程序和gcc -c命令对函数分别进行编译,例如:
(1)分别编写两个函数的源文件:
//fred.c
#include<stdio.h>
void fred(int arg)
{
   printf("fred: you passed %d\n", arg);
}

//bill.c
#include<stdio.h>
void bill(char *arg)
{
   printf("bill: you passed %s\n", arg);
}

(2)编译为目标文件
  gcc -c bill.c fred.c
 
生成目标文件: bill.o  fred.c
-c选项的作用是阻止编译器创建一个完整的程序,如果此时试图创建一个完整的程序将不会成功,因为尚未定义main函数。

(3)为库文件创建头文件
//lib.h
void fred(int);
void bill(char *arg);

(4)创建库文件
  ar crv libfoo.a bill.o fred.o
 
(5)主程序
//program.c
#include "lib.h"

int main()
{
   bill("Hello World.");
   return 0;
}

(6)编译链接主程序
  gcc -o program program.c -L. -lfoo
  ./program
  输出: bill: you passed Hello World.
-L.选项指示编译器在当前目录中查找函数库。

 

共享库

共享库
静态库一个缺点是,当我们同时运行多个应用程序并且它们都使用来自同一个函数库的函数时,就会在内存中有同一函数的多份拷贝,在程序文件自身中也有多份同样的拷贝,这将消耗大量宝贵的内存和磁盘空间。
共享库克服了上述不足。
共享库的保存位置与静态库是一样的,在典型的Linux系统中,标准数学库的共享版本是/usr/lib/libm.so。
程序使用共享库时,它的链接方式是这样的:它本身不再包含函数代码,而是引用运行时可访问的共享代码。当编译好的程序被装载到内存中执行时,函数引用被解析并产生对共享库的调用,如果
有必要共享库才被加载到内存中。
对Linux系统来说,负责装载共享库并解析客户程序函数引用的程序(动态装载器)是ld.so, 也可能是ld-linux.so.2或ld-lsb.so.1.
我们可以通过运行工具ldd来查看程序需要的共享库:
  ldd program

 

Enjoy Linux, Fighting.

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter