❶ 动态链接库的显示加载和隐式加载的区别
两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样的。显式调用麻烦了点,但可以没有相应的lib库;隐式调用,使用起来比较简单,有函数的声明就可以了,但必须有lib库。
在VC中两种方式的具体方法:
一、动态库的隐示调用:
在 VC 工程中直接链接静态输入库XXX.lib,然后即可像调用其它源文件中
的函数一样调用DLL中的函数了。
二、动态库的显式调用:
显式调用动态库步骤:
1、创建一个函数指针,其指针数据类型要与调用的 DLL 引出函数相吻
合。
2、通过 Win32 API 函数LoadLibrary()显式的调用DLL,此函数返回
DLL 的实例句柄。
3、通过 Win32 API 函数GetProcAddress()获取要调用的DLL 的函数地
址,把结果赋给自定义函数的指针类型。
4、使用函数指针来调用 DLL 函数。
5、最后调用完成后,通过 Win32 API 函数FreeLibrary()释放DLL 函数。
❷ VC动态链接库的隐式链接具体配置
在工程中link选项,添加 libmysql.lib连接。
或在代码中写入#pragma comment(lib, "libmysql.lib")
❸ 为什么链接文件不适合随机存取
链接文件分为显式链接和隐式链接,隐式链接就如我们平常所说的链表一样,无法随机存取,而现实链接也是一种链表,但是是用数组表示的链表,所以是可以支持随机“存取”的。
❹ c++没有lib文件任然可以隐式链接
我觉得不需要。
lib是静态库。
有h就好了。
#pragma也不要。
-l和-L指定库就行了。
❺ 1.44mb软盘fat表占多大存储空间
你kb表示错了吧,应该是KB。表项数=1.44MB/1KB=1.44K.由于每个表项占12位(bit),1B(byte字节)=8位。所以fat空间=1.44K*(12/8)B=2.16KB。
❻ 连续组织方式、隐式链接、显式链接,可以用生活中的例子说明一下这些分别是什么意思吗
想象一下,刚刚月考结束,班主任手里拿着一份成绩排名表。
连续分配,就是按照这份排名表依次排座位,可以先排完第一组,然后排第二组,然后第三组……
隐式链接,就是班主任叫一个人的名字,一个人就进教室选座位,座位可以随意选,只要那个座位上没有人就行……
显示链接,就是这个班主任比较懒,只记得班上第一名的名字,但是班上每个人都知道自己下一名的名字,于是,班主任叫第一名进教室选座位,然后第一名选好了,第一名叫第二名进教室选座位,班主任可以坐在一边喝茶了……
操作系统用一张FAT表来记录第一名和第二名,第二名和第三名之间的联系。
班主任手中的排名表就是一个顺序文件,数据是按照怎样的方式组织起来就是通过逻辑结构表现出来的,大家排座位的方式就是文件的物理结构。
❼ lib和dll有什么区别,什么叫静态链接库,什么叫动态连接库
静态链接库与动态链接库区别
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。动态库就是在需要调用其中的函数时,根据函数映射表找到该函数然后调入堆栈执行。如果在当前工程中有多处对dll文件中同一个函数的调用,那么执行时,这个函数只会留下一份拷贝。但是如果有多处对lib文件中同一个函数的调用,那么执行时,该函数将在当前程序的执行空间里留下多份拷贝,而且是一处调用就产生一份拷贝。
静态链接库与静态链接库调用规则总体比较如下:
1、 静态链接库(比较简单):
首先,静态链接库的使用需要库的开发者提供生成库的.h头文件和.lib文件。生成库的.h头文件中的声明格式如下:
extern "C" 函数返回类型 函数名(参数表);
在调用程序的.cpp源代码文件中如下:
#include "../lib.h"
#pragma comment(lib,"..//debug//libTest.lib") //指定与静态库一起链接
其次因为静态链接库是将全部指令都包含入调用程序生成的EXE文件中。因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况,要想用就得全要!要不就都别要!
2、 态链接库:
动态链接库的使用需要库的开发者提供生成的.lib文件和.dll文件。或者只提供dll文件。
首先我们必须先注意到DLL内的函数分为两种:
1) 出函数,可供应用程序调用;
2) LL内部函数,只能在 DLL 程序使用,应用程序无法调用它们。
因此调用程序若想调用DLL中的某个函数就要以某种形式或方式指明它到底想调用哪一个函数。
Ø 对于DLL的导出,可以采用如下方法:
#ifdef WLL_EXPORTS
#define WLL_API __declspec(dllexport)
#else
#define WLL_API __declspec(dllimport)
#endif
这是导出类的宏定义,将导出类必须加上该宏,才能被导出。
此处的WLL_EXPORTS会出现在 projectàsettingsàC++à PreProcessor的PreProcessor definition中,这个MACRO表明其要定义一个导出宏。
当前库编译时,加了WLL_API的类将被导出,而包含该头文件的其他调用DLL或EXE,由于没有定义WLL_API宏,将申明为导入该类。
Ø 动态库函数的调用,可以采用静态链接的方式,主要步骤如下:
包含DLL中导出的头文件。
采用#pragma comment(lib,"..//debug//libTest.lib")导入动态库生成的*.lib头文件。或在projectàsettingsàLinkeràInput的Additional Dependencies中加入lib文件。
将动态库生成的*.dll文件放到EXE或DLL的同一目录下。
Ø 也可以采用动态加载的方式调用,步骤如下:
Another.dll有一个int Add(int x,int y) 函数。则完整的调用过程如下:
typedef int (* FunPtr)(int,int); //定义函数指针
FunPtr funPtr;
Handle handle =LoadLibrary("Another.dll");
funPtr =(FunPtr)GetProcAddress(handle ,"Add");
funPtr(2,3); // 2+3;
FreeLibrary(handle); // 释放载入的动态库
LIB文件
目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。
静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。
动态库一般会有对应的导入库,方便程序静态载入动态链接库,否则你可能就需要自己LoadLibary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。
导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
这也是实际上很多开源代码发布的惯用方式:
1、 预编译的开发包:包含一些.dll文件和一些.lib文件。其中这里的.lib就是导入库,而不要错以为是静态库。但是引入方式和静态库一样,要在链接路径上添加找到这些.lib的路径。而.dll则最好放到最后产生的应用程序exe执行文件相同的目录。这样运行时,就会自动调入动态链接库。
2、 用户自己编译:下载的是源代码,按照readme自己编译。生成很可能也是.dll + .lib(导入库)的库文件
3、 如果你只有dll,并且你知道dll中函数的函数原型,那么你可以直接在自己程序中使用LoadLibary调入DLL文件,GetProcAddress获取函数地址,然后调用。
DLL文件
动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。
动态链接与静态链接的不同之处在于它允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。
使用动态链接代替静态链接有若干优点。DLL 节省内存,减少交换操作,节省磁盘空间,更易于升级,提供售后支持,提供扩展 MFC 库类的机制,支持多语言程序,并使国际版本的创建轻松完成。
API 就是应用程序编程接口。它是能用来操作组件、应用程序或者操作系统的一组函数。典型的情况下,API 由一个或多个提供某种特殊功能的 DLL 组成。
DLL 是一个文件,其中包含了在 Microsoft Windows下运行的任何应用程序都可调用的函数。运行时,DLL 中的函数动态地链接到调用它的应用程序中。无论有多少应用程序调用 DLL 中的某个函数,在磁盘上只有一个文件包含该函数,且只在它调入内存时才创建该 DLL。 您听到最多的 API 可能是 Windows API,它包括构成 Windows 操作系统的各种 DLL。每个 Windows 应用程序都直接或间接地与 Windows API 互动。Windows API 保证 Windows 下运行的所有应用程序的行为方式一致。
随着 Windows 操作系统的发展,现已发布了几个版本的 Windows API。Windows 3.1 使用 Win16 API。Microsoft Windows NT、Windows 95 和 Windows 98平台使用 Microsoft Win32 API。除 Windows API 外,其他一些 API 也已发布。例如,邮件应用程序编程接口 (MAPI) 是一组可用于编写电子邮件应用程序的 DLL。API 传统上是为开发 Windows 应用程序的 C 和 C++ 程序员编写的,但其他的编程语言(包括VBA)也可以调用 DLL 中的函数。因为大部分 DLL 主要是为 C 和 C++ 程序员编写和整理说明的,所以调用 DLL 函数的方法与调用 VBA 函数会有所不同。在使用 API 时必须了解如何给 DLL 函数传递参数。
警告:调用 Windows API 和 其他 DLL 函数可能会给您的应用程序带来不良影响。从自己的代码中直接调用 DLL 函数时,您绕过了 VBA 通常提供的一些安全机制。如果在定义或调用 DLL 函数时出现错误(所有程序员都不可避免),可能会在应用程序中引起应用程序错误(也称为通用性保护错误,或 GPF)。最好的解决办法是在运行代码以前保存该项目,并确保了解 DLL 函数调用的原理。
❽ 比较顺序存储和链接存储两种存储结构的优缺点。(参考教材4.1)
/*****************************************************
顺序表算法
严格按照《数据结构C语言版》实现
敬请指正
vincent
2006-12-28
******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int Status;
typedef int ElemType;
/*C中的函数指针类型*/
typedef Status (*cmp)(ElemType x,ElemType i);
typedef void (*vis)();
struct SqList{
ElemType *elem;
int length;
int listsize;
};
/*创建新的顺序表*/
Status InitList(SqList &L);
/*销毁顺序表*/
Status DestroyList(SqList &L);
/*如果顺序表为空TRUE 否则FALSE*/
Status ListEmpty(SqList &L);
/*返回顺序表长度*/
int ListLength(SqList &L);
/*返回指定位置的元素*/
ElemType GetElem(SqList &L,int i,ElemType *e);
/*定位指定元素,如果有返回第一个匹配的元素的位置*/
int LocateElem(SqList &L,ElemType e,cmp f);
/*int LocateElem_sq(SqList &L,ElemType e);*/
/*返回当前元素的前一个元素*/
ElemType PriorElem(SqList &L,int pos,ElemType *pre_e);
/*返回当前元素的后一个元素*/
ElemType NextElem(SqList &L,int pos,ElemType *next_e);
/*清空表*/
Status ClearList(SqList &L);
/*在指定位置插入元素*/
Status ListInsert(SqList &L,int i,ElemType e);
/*删除指定位置的元素*/
Status ListDelete(SqList &L, int i, ElemType e);
/*遍历顺序表*/
Status ListTraverse(SqList &L, vis v);
/*在顺序表中比较元素e*/
Status compare(ElemType x,ElemType i);
/*visit 函数在遍历表时返回当前元素*/
void visit(SqList &L);
main(){
int i,t ;
ElemType a;
int b;
cmp f;
SqList L;
ElemType *e;
if(!InitList(L)){
printf("E001\n");
exit(ERROR);
}
printf("请输入数字,默认为5个\n");
for(i =1;i <= 5; i++){
int z[5] ;
scanf("%d",&z[i-1]);
if (!ListInsert(L,i,z[i-1])){
printf("E002\n");
exit(ERROR);
}
}
printf("结果是:\n");
for(i = 1 ; i <= L.length;i++){
printf("%d\n",GetElem(L,i,e));
}
/*返回表长*/
printf("%d\n",ListLength(L));
a=3;
printf("%d\n",LocateElem(L,a, f));
DestroyList(L);
}
/*构造一个空表*/
Status InitList(SqList &L) {
L.elem = (ElemType *) malloc(LIST_INIT_SIZE * sizeof(ElemType));
if(!L.elem)exit(OVERFLOW);
L.length = 0;
L.listsize = LIST_INIT_SIZE;
return OK;
}
/*销毁一个表*/
Status DestroyList(SqList &L) {
if(!L.elem)exit(ERROR);
free(L.elem);
L.elem = NULL;
//L = NULL;
return OK;
}
/*如果顺序表为空TRUE 否则FALSE*/
Status ListEmpty(SqList &L){
if(L.elem == NULL){
return TRUE;
}
else {
return FALSE;
}
}
/*返回顺序表长度*/
int ListLength(SqList &L){
if(!L.elem)exit(ERROR);
return L.length;
}
/*返回指定位置的元素*/
ElemType GetElem(SqList &L,int i,ElemType *e){
if(!L.elem || i > L.length || i < 1 )exit(ERROR);
/*e = L.elem + sizeof(ElemType)*(i-1);*/
e = L.elem + i - 1;
return *e;
}
/*定位指定元素,如果有返回第一个匹配的元素的位置*/
int LocateElem(SqList &L,ElemType e,cmp f){
//f = compare(ElemType x,int i);
int z,s;
ElemType *y;
if(!L.elem) exit(ERROR);
for(z=0;z<= L.length;z++){
/*y = L.elem + sizeof(ElemType)*z;*/
y = L.elem + z;
s = f(*y,e);
if (s == TRUE) return z;
}
return 0;
}
/*在顺序表中比较元素e*/
Status compare(ElemType x,ElemType i){
if (x == i) return TRUE;
return FALSE;
}
/*返回当前元素的前一个元素*/
ElemType PriorElem(SqList &L,int pos,ElemType *pre_e){
if(pos > L.length || pos < 2) exit(ERROR);
pre_e = L.elem + pos -1;
return *pre_e;
}
/*返回当前元素的后一个元素*/
ElemType NextElem(SqList &L,int pos,ElemType *next_e){
if(pos > L.length -1 || pos < 1)exit(ERROR);
next_e = L.elem + pos +1;
return *next_e;
}
/*清空表将表中元素去掉,设置长度为0*/
Status ClearList(SqList &L){
int i;
if(!L.elem)exit(ERROR);
free(L.elem);
L.length = 0;
return OK;
}
/*在指定位置插入元素*/
Status ListInsert(SqList &L,int i,ElemType e){
ElemType *p,*q,*newbase;
if(i <1 || i > L.length +1){
printf("E004\n");
return(ERROR);
}
if(L.length >= L.listsize){
newbase = (ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase)exit(OVERFLOW);
L.elem = newbase;
L.listsize += LISTINCREMENT;
}
q = &(L.elem[i -1]);
for(p = &(L.elem[L.length -1]);p >= q; --p) *(p+1) = *p;
*q = e ;
++L.length;
return OK;
}
/*删除指定位置的元素*/
Status ListDelete(SqList &L, int i, ElemType e){
ElemType *p,*q;
if(i <1 || i > L.length +1)return(ERROR);
p = &(L.elem[i - 1]);
e = *p;
q = L.elem + L.length -1;
for(++p;p <= q;++p) *(p-1) = *p;
--L.length;
return OK;
}
❾ 链接分配文件:隐式链接 显示链接,求他们的区别
隐式链接指针在磁盘上,每一次都要读取磁盘。显示链接将磁盘上文件的链式结构用内存的一张FAT表去描述,查找时可以在内存中进行。定位后再读磁盘。速度比隐式快很多。
❿ 隐式链接分配会有内部碎片吗也就是说,如果一个文件的末尾部分只分配到一个磁盘块的一部分,那
隐式链接分配的主要问题在于:
其只适合于顺序访问,对随机访问的效率及其低效。此外,其可靠性较差,任何一个指针出现问题,都会导致整个链的断开。
可以将几个盘块组成一个簇,然后以簇为单位进行分配,会减少查找指定块的时间,但是会增加内部碎片。
如果将一个逻辑文件存储到外存上,并不要求为整个文件分配一块连续的空间,而是可以将文件装到多个离散的盘块中,这样就可以消除连续分配的缺点。
采用链接分配方式时,可通过在每个盘块上的链接指针,将同属于一个文件的多个离散盘块链接成一个链表,把这样形成的物理文件称为链接文件。链接分配采取离散分配方式,消除了外部碎片,故而显着地提高了外存空间的利用率,并且对文件的增、删、改、查十分方便。链接方式可分为隐式链接和显示链接两种形式。