静态链接和动态链接的区别

您所在的位置:网站首页 静态链接和动态链接的差别是什么 静态链接和动态链接的区别

静态链接和动态链接的区别

2024-06-28 04:56| 来源: 网络整理| 查看: 265

首先要知道的是:一个程序需要通过编译,链接两个过程,其中编译是将代码转化为二进制程序.obj文件,链接是将代码中的静态链接和动态链接做相应的动作。

静态链接:

静态链接是由.lib文件和.h文件组成的;

静态编译的格式也就是经常被写到的#include的形式,其中的#include的作用是进行预编译,编译器会将尖括号中的.h文件找出,具体可见编译器的Include文件夹,里面包含的就是各种各样的.h文件 其中.h文件主要是记录的函数的定义,一般一个.h文件会由其对应的.lib文件但是像stdio.h这样的标志库对应的是libc.lib。也就是说,当我们写下了printf时,也就是在 libc.lib中找到的源码。

.lib文件主要记录的是.h中函数的实现过程,属于二进制文件的范围,.lib也就是一堆.obj文件的集合。我们写的.lib程序如果引用了其他的静态库,也就会将其他库的代码拿过来引用,而像libc中函数实现是通过调用更底层的库来实现。

静态链接库的创建方法:

在这里插入图片描述 创建static library文件 在这里插入图片描述 将函数声明写在.cpp文件上; 在这里插入图片描述 将函数的声明写在.h头文件上;编译生成 在这里插入图片描述 在这里插入图片描述 生成.h和.lib文件;

静态链接库的使用方法:

新建一个win32控制台程序,将需要使用的.lib文件和.h文件放入该文件目录下;

在这里插入图片描述 #include “StdAfx.h” 让编译器知道使用了这个头文件中声明的函数; #pragma comment(lib,“1.lib”) 声明函数体的位置; 在这里插入图片描述 或者可将#pragma comment(lib,“1.lib”)替换为将lib文件直接写入工程的设置中 在这里插入图片描述 这样可以实现相同的效果。

静态编译是通过将.lib文件中的字节码文件完全复制一份到源文件中,因此当我们进行跟踪代码的时候,会发现地址出现在一个低地址的位置。

在这里插入图片描述

动态编译

动态链接库由两部分组成:.lib文件和.DLL文件

动态链接的创建方法:

在这里插入图片描述 创建dynamic-link library文件;

在这里插入图片描述在这里插入图片描述

在.h文件中对函数进行声明,在.cpp文件中对函数体进行定义; .h文件中声明的意思:extern表示将函数声明为全局函数,“c”表示以c语言的方式编译,_declspec(dllexport)表示将函数导出,编译器会根据这一行填写dll的导出表。 将cpp文件编译编译,生成.dll文件和.lib文件,lib文件函数表示代码在在哪里,dll文件存放的就是字节码文件

其中“C”的作用,表示以c语言的方式编译,c和c++的区别之一就是c++存在重载,这里也是一种重载,通过将函数的名字进行随机字符的添加,防止名字相同。 下图为以c++的方式导出 extern _declspec(dllexport) int add(int x,int y); 在这里插入图片描述下图为以"C"的方式导出得到: 在这里插入图片描述

动态链接库的使用:

隐式调用: 将dll和lib文件放入工程目录下; 使用#pragma comment(lib,“dlltest.dll”);声明需要使用lib文件 使用extern _declspec(dllimport) int add(int x,int y);声明需要使用的函 在这里我使用了c++的方式导入,如果在制作dll的使用使用了c的方式导入,在这里也需要以c的方式导入。 在这里插入图片描述

显示调用: 下图中就是将dll以显示调用的方式引用; LoadLibrary函数将dll文件加载进入4GB的空间中,然后将其作为一个句柄(地址),通过GetProcAddress函数在dll文件的导出表找到对应的add函数的偏移地址将其赋值给对应的格式的函数指针,再使用这个偏移地址+dll在4GB空间中开始的位置,得到的就是这个函数的地址。 在这里插入图片描述 使用动态连接库,函数出现一个高地址的位置 在这里插入图片描述使用动态链接库隐藏名字: 创建一个.def文件,在其中声明add函数的序号为10 同时无名字 在这里插入图片描述可以看到在这个dll文件中,函数是没有名字的,以序号的方式导出 在这里插入图片描述 当使用这种方式来导出函数,不能使用GetProAddress来得到寒素的地址,暂时我也未找到合适的api来寻找函数地址,但是可以通过对于导出表的解析,通过序号来得到函数的地址。

显示调用和隐式调用的区别:

显示调用通过动态的LoadLibrary方式来导入,是需要执行函数的,所以不写在事先写入到导入表中;而隐式调用通过链接器来实现,可以将需要导入的dll写入到pe头的导入表中,这样,当我们执行这个程序的时候,操作系统就根据导入表将函数的地址写入到某位置。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3