简介

链接器(Linker)是一个程序,将一个或多个由 编译器或汇编器生成的目标文件 外加 库链接 为一个 可执行文件 。

//将编译器编译好的无地址相关信息的目标代码根据平台不同组合起来,加入地址信息

目标文件是包括 机器码和链接器可用信息的 程序模块。简单的讲,链接器的工作就是解析未定义的符号引用,将目标文件中的占位符替换为符号的地址。链接器还要完成程序中各目标文件的 地址空间的组织,这可能涉及 重定位工作。

模式

大多数现代操作系统都提供 静态链接 和 动态链接 两种形式。

///

静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。  

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。


///

“每一个lib文件就是若干函数(假设只有函数)的定义 ” 
lib库有两种 , 一种是 包含了函数所在DLL文件和文件中函数位置的信息,称为导出库 ;一种是 包含函数代码本身 , 一般现有的DLL,用的是前一种库 ;


lib有静态lib和动态lib之分。

静态lib将导出声明和实现都放在lib中。编译后所有代码都嵌入到宿主程序

动态lib相当于一个h文件,是对实现部分(.dll文件)的导出部分的声明。编译后只是将导出声明部分编译到宿主程序中,运行时候需要相应的dll文件支持


“通过#include包含这些函数声明的头文件后,我们的应用程序就可以使用lib文件中的函数”

还要指定编译器链接相应的库文件。在IDE环境下,一般是一次指定所有用到的库文件,编译器自己寻找每个模块需要的库;在命令行编译环境下,需要指定每个模块调用的库。 



“那他和直接给出那个函数定义的文件,比如.cpp文件,和头文件有什么区别,静态链接库有什么用” 

cpp文件是源代码,库文件是编译后的二进制代码,比如你可以调用Windows的API,但是不能看到其源代码一样。



///


例子:

静态链接库(Lib)
在VC++6.0中new一个名称为libTest的static library工程,

并新建lib.h和lib.cpp两个文件,lib.h和lib.cpp的源代码如下:

//文件:lib.h
 #ifndef LIB_H
 #define LIB_H
 extern "C" int add(int x,int y);   //声明为C编译、连接方式的外部函数
 #endif

 //文件:lib.cpp
 #include "lib.h"
 int add(int x,int y)
 {
 return x + y;
 }

  编译这个工程就得到了一个.lib文件,这个文件就是一个函数库,它提供了add的功能。将头文件和.lib文件提交给用户后,用户就可以直接使用其中的add函数了。

  标准Turbo C2.0中的C库函数(我们用来的scanf、printf、memcpy、strcpy等)就来自这种静态库。

下面来看看怎么使用这个库,在libTest工程所在的工作区内new一个libCall工程。libCall工程仅包含一个main.cpp文件,它演示了静态链接库的调用方法,其源代码如下:

 

 

#include <stdio.h>
#include "../lib.h"//不可丢失
#pragma comment( lib, "..//debug//libTest.lib" )  //指定与静态库一起连接
int main(int argc, char* argv[])
{
printf( "2 + 3 = %d", add( 2, 3 ) );
}

  静态链接库的调用就是这么简单,或许我们每天都在用,可是我们没有明白这个概念。代码中#pragma comment( lib , "..//debug//libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接


/

事例


在 IBM大型主机比如OS/360上,链接器是 linkage editor;在GNU/Linux系统上的链接器是 GNU ld。