您的位置:首页 > 其它

[初]静态链接和动态链接的一些问题

2007-02-26 16:02 465 查看
静态链接和动态链接的一些问题

参考资料:
1 <<c&c++深度探索>>
2 http://www.graphics.net.cn/document/vc/003/348.asp

要生成动态链接?
静态链接有两个特点:
l链接后产生的可执行文件包含了所有需要调用的函数的代码,因此占用磁盘宁
间较大;
2如果有多个(调用相同库函数的)进程在内存中间时运行,内存中就存有多份
相同的库函数代码,因此占用内存空间较多。
动态链接就是为了解决这些问题而诞生的技术。顾名思义,动态链接的意思就是在程
序装载入内存的时候才真正把库函数代码链接进来确定它们的地址,并且就算有多个程
序运行,内存也只存在一份函数代码。

Linux如何生成动态库
/* Example code main.c */
int fun(void);
int main(void)
{
fun():
return 0;
}
/* Example code fun.c */
int fun(void)
{
return 0;
}

这里有两个C文件,其中,我们要把包含fun函数的那个文件编译成PIC,放到动态库里去:
$gcc -c -fPIC fun.c
$gcc -shared -o libfun.so fun.o  <-----就是这行代码
然后:
$gcc main.c -L. –lfun
生成a.out

这时已经成功生成可执行文件,不过,要使系统能够使用动态库,必须让系统知道放置动态库的位置,
最简单的办法是设置LD_LIBRARY_PATH环境变量(在window底下是LIBRARY_PATH)

动态库的两个相关概念?
1静态绑定(static blnding)
使用静态绑定的程序在一开始载入内存的时候,载入程序就会把程序所有调用到的
动态代码的地址算出、确定下来。这种方式使程序刚运行时的初始化时间较长,不过一
但完成动态装载,程序的运行速度就很快。
2动态绑定(dynamic binding)
使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码
时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程
序又需要调用另外某块动态代码时,载入程序才又去计算这部分代码的逻辑地址。所以,
这种方式侄程序初始化时间较短,但运行期间的性能比不上静态绑定的程序。

Linux下如何生成静态库
两个命令gcc和ar
gcc -c filename1.c
ar -r libabc.a filename1.o

/* Example code 13-01, file name: 1301.c */

extern int global;

void f(void);

int main(void)
{
f();
++global;
return 0;
}
/* Example code 13-01a, file name: 1301a.c */

extern void g(void);
int global = 0;
void f(void) {
printf("in the f()");
g();
};
/* Example code 13-01b, file name: 1301b.c */

static int local = 1;
void g(void) { --local; }
1
gcc –c 1301a.c 1301b.c
生成 1301a.o 1301b.o

2
ar rc libtest.a 1301a.o 1301b.o
生成 libtest.a (静态库文件名通常是libxxx.a)

3
gcc 1301.c –L. -ltest
生成 a.exe (在windows平台自动生成a.exe,在类unix平台则生成a.out)

Window下的动态链接技?
SDK编程笔记 - DLL篇
1. 动态链接之含义

在链接应用程序时常使用所谓“静态链接”的方法,即将各个目标文件(.obj)、运行时函数库(.lib)以及已编译的资源文件(.res)链接到一起,形成一个可执行文件(.exe)。使用静态链接时,可执行文件需要使用的各种函数和资源都已包含到文件中。这样做的缺点是对于多个程序都使用的相同函数和资源要重复链接到exe文件中,使程序变大、占用内存增加。 “动态链接”是将一些公用的函数或资源组织成动态链接库文件(.dll),当某个需要使用dll中的函数或资源的程序启动时(准确的说是初始化时),系统将该dll映射到调用进程的虚拟地址空间、增加该dll的引用计数值,然后当实际使用到该dll时操作系统就将该dll载入内存;如果使用该dll的所有程序都已结束,则系统将该库从内存中移除。使用同一dll的各个进程在运行时共享dll的代码,但是对于dll中的数据则各有一份拷贝(当然也有在dll中共享数据的方法)。 动态链接库中可以定义两种函数:输出函数和内部函数。输出函数可以被其他模块调用,内部函数只能被动态链接库本身调用。动态链接库也可以输出数据,但这些数据通常只被它自己的函数所使用。

2. 动态链接的优点

→节约内存;
→使应用程序“变瘦”;
→可单独修改动态链接库而不必与应用程序重新链接;
→可方便实现多语言联合编程(比如用VC++写个dll,然后在VB中调用);
→可将资源打包;
→可在应用程序间共享内存
→......

3. 关于扩展名

动态链接库的标准扩展名是dll,其他如exe,drv,fon也可作为扩展名,但只有扩展名为dll的动态链接库才能被Windows自动载入。如果使用其它扩展名的动态链接库,则调用动态链接库的程序中必须使用LoadLibrary或LoadLibraryEx载入动态链接库模块。

4. 用SDK创建一个简单的dll文件

在VC++中选择新建一个Win32 Dynamic-Link Library。需要建立一个c/c++ head file和一个c/c++ source file并加入工程。头文件中内容为输出函数的声明,源文件中内容为DllMain函数和输出函数的定义。下面是一个最简单的例子。

//dlldemo.h
#ifdef __cplusplus
#define EXPORT extern "C" __declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif

EXPORT void CALLBACK DllFoo(void) ;

//dlldemo.c
#include <windows.h>
#include "dlldemo.h"

int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
return TRUE ;
}

EXPORT void CALLBACK DllFoo(void)
{
MessageBox(NULL,TEXT("This function is exported from a DLL"),TEXT("DllFoo"),MB_OK) ;
return ;
}

头文件预处理中的__declspec是微软增加的“C扩展类存储属性”(C Extended Storage-Class Attributes),它指明一个给出的实例被存储为一种微软特定的类存储属性,可以为thread,naked,dllimport或dllexport. [MSDN原文:The extended attribute syntax for specifying storage-class information uses the __declspec keyword, which specifies that an instance of a given type is to be stored with a Microsoft-specific storage-class attribute (thread, naked, dllimport, or dllexport).] 输出函数必须指明为CALLBACK。 DllMain是dll的入口点函数。也可以不写它。DllMain必须返回TRUE,否则系统将终止程序并弹出一个“启动程序时出错”对话框。 编译链接后,得到动态链接库文件dlldemo.dll和输入库文件dlldemo.lib。

5.使用dll的两种方式

方法一: load-time dynamic linking
在要调用dll的应用程序链接时,将dll的输入库文件(import library,.lib文件)包含进去。具体的做 法是在源文件开头加一句#include ,然后就可以在源文件中调用dlldemo.dll中的输出文件了。

方法二: run-time dynamic linking
不必在链接时包含输入库文件,而是在源程序中使用LoadLibrary或LoadLibraryEx动态的载入dll。
主要步骤为(以demodll.dll为例):

1) typedef函数原型和定义函数指针。
typedef void (CALLBACK* DllFooType)(void) ;
DllFooType pfnDllFoo = NULL ;
2) 使用LoadLibrary载入dll,并保存dll实例句柄
HINSTANCE dllHandle = NULL ;
...
dllHandle = LoadLibrary(TEXT("dlldemo.dll"));
3) 使用GetProcAddress得到dll中函数的指针
pfnDllFoo = (DllFooType)GetProcAddress(dllHandle,TEXT("DllFoo")) ;
注意从GetProcAddress返回的指针必须转型为特定类型的函数指针。
4)检验函数指针,如果不为空则可调用该函数
if(pfnDllFoo!=NULL)
DllFoo() ;
5)使用FreeLibrary卸载dll
FreeLibrary(dllHandle) ;

使用run-time dynamic linking 比较麻烦,但有它的好处(下面讨论)。MSDN中有一篇文章DLLs the Dynamic Way讨论使用c的宏创建一个基类pDll完成以上复杂的操作,使用时只需定义一个类继承自类pDll并 对类和函数使用宏。
以上两种方法都要求应用程序能找到dll文件,Windows按以下顺序寻找dll文件:

1)应用程序所在目录。
2)当前目录。
3)Windows 9x : System目录; Windows 2000/NT : System32 目录
4)Windows 2000/NT的System目录。
5)Windows所在目录。
6)环境变量path中的路径。

如果系统不能找到dll文件,将结束调用dll的进程并弹出一个“启动程序时出错”对话框,告诉你“找 不到所需的dll文件-XXX.dll”。

6 使用运行时的动态链接(Run-Time Dynamic Linking)有什么好处?

如果使用载入时的动态链接(Load-Time Dynamic Linking),当dll文件丢失时,调用此dll的程序将不能运行,你将会看到一个“启动程序时出错”对话框。而如果在运行时载入dll,你有机会处理这个错误,至少可以比较“温柔”的结束程序。
如果dll改变了,使用load-time dynamic linking的程序可能会终止,而使用run-time dynamic linking 的程序只有当调用的函数在新的dll中不存在时才会出错。

7 使用纯资源dll

一般只在其c文件中写一个空的DllMain,然后向工程中插入资源,最后编译为dll文件。纯资源dll没有任何输出函数,因此不会生成.lib文件,所以必须在运行时用LoadLibrary载入。

8 在dll中使用共享数据(摘自programming windows)

// shared memory section (requires /SECTION:shared,RWS in link options)
#pragma data_seg ("shared")
int iTotal = 0 ;
WCHAR szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '/0' } ;
#pragma data_seg ()

#pragma comment(linker,"/SECTION:shared,RWS")

第一个#pragma叙述建立资料段,这里命名为shared。您可以将这段命名为任何一个您喜欢的名字。在这里的#pragma叙述之后的所有初始化了的变数都放在shared资料段中。第二个#pragma叙述标示段的结束。对变数进行专门的初始化是很重要的,否则编译器将把它们放在普通的未初始化资料段中而不是放在shared中。 连结器必须知道有一个「shared」共享资料段。在「Project Settings」对话方块选择「Link」页面标签。选中「STRLIB」时在「Project Options」栏位(在Release和Debug设定中均可),包含下面的连结叙述: /SECTION:shared,RWS 字母RWS表示段具有读、写和共用属性。或者,您也可以直接用DLL原始码指定连结选项,就像我们在STRLIB.C那样: #pragma comment(linker,"/SECTION:shared,RWS")

the end

参考资料:http://www.graphics.net.cn/document/vc/003/348.asp

动态链接库的一些名词

参考资料:

http://blog.csdn.net/gofishing/archive/2006/05/09/715052.aspx

1、什么是动态链接库?
它不是应用程序,不能直接运行,也不能接收消息。dll是一系列函数的集合,可以简单理解为把一些函数放到了一个文件里面,这些函数可以被其它程序和dll调用。一个dll可以同时被几个程序或其它dll调用,这应该是它的特点。
2、windows api与dll
windows api中的所有函数均包含在dll中,当然不会是一个dll。其中最为重要的3个windows api的dll文件是:Kernel32.dll 主要是管理内存、进程和线程的函数的集合;User32.dll 执行用户界面的任务的函数(比如:窗口的创建销毁放大缩小、消息的传递等等与用户相关的操作);GDI32.dll 包含用于画图和显示文本的各个函数;
3、静态库和动态库
静态库是把程序运行时需要使用的函数编译在一个二进制文件中,扩展名为.lib。当程序link时把静态库中的二进制数据和程序其它数据放到一起。程序运行时不在需要lib和dll文件的支持。这样做的坏处是开发出来的程序占用磁盘空间较大。特别是windows系统中本来就有或很多程序运行都需要的函数完全没有必要每次开发程序时都要使用各自的静态库。
而动态库在开发时仅是把dll中的函数名和参数放到应用程序中,应用程序运行时根据函数名和参数调用dll中的函数来运行,这样操作系统中的应用程序可以同时使用同一个dll。可以有效地节省硬盘空间,当然这样做使得程序设计更有层次。也有利于软件工程师的分工和信息安全。
4、引入库和动态库
引入库和动态库是成对出现的,在编译dll的时候会同时产生一个引入库,扩展名为lib。lib中仅含有dll中的函数名和参数,真正的函数体在动态库中。两个的关系大概相当于.h和.cpp文件之间的关系。在编写程序的过程中
5、引入库和静态库
引入库和静态库的扩展名均为*.lib,但是引入库仅包含一些函数名和参数信息,没有函数体,是为调用动态库服务的,它和动态库的关系相当于.h文件和.cpp文件之间的关系;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: