精华内容
下载资源
问答
  • 动态库的显示链接和隐式链接

    千次阅读 2016-10-11 17:24:46
     我们通常把一些公用函数制作成函数库,供其它程序使用。 函数库分为静态库和动态库两种。 ... (1)静态库在程序...本节将进行讲解动态库的显示链接和隐式链接,在下一节说明静态库的引用 1.动态库的显示链
    

    我们通常把一些公用函数制作成函数库,供其它程序使用。

    函数库分为静态库和动态库两种。

      (1)静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

      (2)动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

    本节将进行讲解动态库的显示链接和隐式链接,在下一节说明静态库的引用

    1.动态库的显示链接

    对应的生成动态库的代码可以写成下面的形式:

    #define DLL_API __declspec(dllexport)

    extern  "C"    int   DLL_API    add(int x, int y)

    {

          return (x+y);

    }

    个是写动态库一定要曝露出来的接口,这个一定要注意,没有这句话动态库是不起任何作用的。

    生成dll的方法有两种,一种是在建立项目的时候就把他建立成dll,要么就是先建立一个Windows控制台程序,然后设置项目的属性生成dll.

    对应的调用动态库的.c文件的写法:
    #include "windows.h"
    #include "stdio.h"

    typedef int(*lpAddFun)(int,int);//typedef定义一个指向函数类型的指针
    //先复习一下指向函数的指针
    /*如果在程序中定义了一个函数,在编译时,编译系统为函数代码段分配一段存储空间
    这段存储空间的起始地址称为这个函数的指针
    */
    int main(int argc, char* argv[])
    {
        char* szStr = "demodll.dll";
        WCHAR wszClassName[256];
        memset(wszClassName, 0, sizeof(wszClassName));
        MultiByteToWideChar(CP_ACP, 0, szStr, strlen(szStr) + 1, wszClassName,
            sizeof(wszClassName) / sizeof(wszClassName[0]));
        HINSTANCE hDll;   //DLL句柄
        lpAddFun addFun;  //函数指针
        //数组名代表首元素地址
        hDll = LoadLibrary(wszClassName);
        if (hDll != NULL)
        {
            addFun = (lpAddFun)GetProcAddress(hDll, "add");

            if(addFun != NULL)
            {
                int result = (*addFun)(2, 3);
                printf("%d\n", result);
            }
            FreeLibrary(hDll);
        }
        return 0;
    }

    这里需要注意的一个问题是   LoadLibrary()对应的形参是一个指向WHAR型的指针,而我们正常的是一个char 字符串,所以上面那些语句进行转化的是。

    2.动态库的隐式链接

    将生成的.dll和.lib都要放在工程目录下,然后用语句  pragma comment(lib,"...  .lib");

    然后再把附加库目录和附加依赖项都清除就可以了。



    展开全文
  • 链接库的链接方式 1 确定要使用的链接方法: 有两种类型的链接:隐式链接和显式链接。 隐式链接 应用程序的代码调用导出 DLL 函数时发生隐式链接。当调用可执行文件的源代码被编译或被汇编时,DLL 函数调用在对象...

    定义:运行时库 静态库 动态库

    • 运行时库:Unix中一个典型的运行时库例子就是libc,它包含标准的C函数,如,print(),exit()等等,用户能创建他们自己的运行库(在Windows中是DLL),而具体的细节依赖编译器和操作系统的。

    • 静态库:函数和数据被编译进一个二进制文件(通常扩展名为.lib),静态库实际上是在链接时被链接到EXE的,库本身不需要与可执行文件一起发行。

    • 动态库:用VC++创建的动态库包含两个文件,一个lib文件和一个dll文件,这个lib文件就是引入库,不是静态库,引入库有时也叫输入库或导入库。

    注:windows操作系统下动态库和运行时库的扩展名都是.dll,COM组件的扩展名也是.dll,动态库的引入库和静态库的扩展名都是.lib。

    静态库的特点和创建过程

    静态库之所以称为【静态库】,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

      试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结如下:

    • 静态库对函数库的链接是放在编译时期完成的。

    • 程序在运行时与函数库再无瓜葛,移植方便。

    • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

    如下图是静态库创建过程:

    动态库的特点和创建过程

    为什么还需要动态库?

      为什么还需要动态库,其实也就是静态库的特点导致。

    • 空间浪费是静态库的一个问题。

    • 另一个问题是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库libxx.lib更新了,所有使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,只是一个很小的改动,却导致整个程序重新下载,全量更新)。

      动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行时才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新

    动态库特点总结:

    • 动态库把对一些库函数的链接载入推迟到程序运行的时期。 

    • 可以实现进程之间的资源共享。(因此动态库也称为共享库)

    • 将一些程序升级变得简单。

    • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。 

     

    Windows与Linux执行文件格式不同,在创建动态库的时候有一些差异。

    • 在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字

    • Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。

    windows下调用动态库的方法:

    1 隐式加载:即在程序中包含lib文件和.h文件,隐式链接有时称为静态加载或加载时动态链接。例如:

    #include "somedll.h"

    #pragma comment( lib, "somedll.lib")

    然后就可以直接调用此dll中的函数,注意运行时仍然需要somedll.dll。

    2 显示加载:使用loadlibrary,GetProcAddress,FreeLibrary,不需要.h文件和.lib文件,但是要知道函数的原型。显式链接有时称为动态加载或运行时动态链接

    3 区别:如果在进程启动时未找到 DLL,操作系统将终止使用隐式链接的进程。同样是在此情况下,使用显式链接的进程则不会被终止,并可以尝试从错误中恢复。

    有关Win32 DLL,Unix共享库及普通库的详细库结构信息请参考《链接器与加载器》一书。

    链接库的链接方式

    1 确定要使用的链接方法:

    有两种类型的链接:隐式链接和显式链接。

    隐式链接

    1. 应用程序的代码调用导出 DLL 函数时发生隐式链接。当调用可执行文件的源代码被编译或被汇编时,DLL 函数调用在对象代码中生成一个外部函数引用。若要解析此外部引用,应用程序必须与 DLL 的创建者所提供的导入库(.LIB 文件)链接。

    2. 导入库仅包含加载 DLL 的代码和实现 DLL 函数调用的代码。在导入库中找到外部函数后,会通知链接器此函数的代码在DLL 中。要解析对 DLL 的外部引用,链接器只需向可执行文件中添加信息,通知系统在进程启动时应在何处查找 DLL 代码。

    3. 系统启动包含动态链接引用的程序时,它使用程序的可执行文件中的信息定位所需的 DLL。如果系统无法定位 DLL,它将终止进程并显示一个对话框来报告错误。否则,系统将 DLL 模块映射到进程的地址空间中。

    4. 如果任何 DLL 具有(用于初始化代码和终止代码的)入口点函数,操作系统将调用此函数。在传递到入口点函数的参数中,有一个指定用以指示 DLL 正在附带到进程的代码。如果入口点函数没有返回 TRUE,系统将终止进程并报告错误。最后,系统修改进程的可执行代码以提供 DLL 函数的起始地址。

    5. 与程序代码的其余部分一样,DLL 代码在进程启动时映射到进程的地址空间中,且仅当需要时才加载到内存中。因此,由 .def 文件用来在 Windows 的早期版本中控制加载的 PRELOAD 和 LOADONCALL 代码属性不再具有任何意义。

    显式链接
    大部分应用程序使用隐式链接,因为这是最易于使用的链接方法。但是有时也需要显式链接。下面是一些使用显式链接的常见原因:

    1. 直到运行时,应用程序才知道需要加载的 DLL 的名称。例如,应用程序可能需要从配置文件获取 DLL 的名称和导出函数名。

    2. 如果在进程启动时未找到 DLL,操作系统将终止使用隐式链接的进程。同样是在此情况下,使用显式链接的进程则不会被终止,并可以尝试从错误中恢复。例如,进程可通知用户所发生的错误,并让用户指定 DLL 的其他路径。如果使用隐式链接的进程所链接到的 DLL 中有任何 DLL 具有失败的 DllMain 函数,该进程也会被终止。同样是在此情况下,使用显式链接的进程则不会被终止。

    3. 因为Windows 在应用程序加载时加载所有的 DLL,故隐式链接到许多 DLL 的应用程序启动起来会比较慢。为提高启动性能,应用程序可隐式链接到那些加载后立即需要的 DLL,并等到在需要时显式链接到其他 DLL。

    4. 显式链接下不需将应用程序与导入库链接。如果 DLL 中的更改导致导出序号更改,使用显式链接的应用程序不需重新链接(假设它们是用函数名而不是序号值调用 GetProcAddress),而使用隐式链接的应用程序必须重新链接到新的导入库。

    下面是需要注意的显式链接的两个缺点:

                 1. 如果 DLL 具有 DllMain 入口点函数,则操作系统在调用 LoadLibrary 的线程上下文中调用此函数。如果由于以前调用了LoadLibrary 但没有相应地调用 FreeLibrary 函数而导致 DLL 已经附加到进程,则不会调用此入口点函数。如果 DLL 使用 DllMain 函数为进程的每个线程执行初始化,显式链接会造成问题,因为调用 LoadLibrary(或AfxLoadLibrary)时存在的线程将不会初始化。服务器负载高,性能下降,导致无法及时的处理客户端的请求,可能是服务器硬件本身需要升级,另外一方面是程序自身的bug导致的吞吐量不够,性能低、还有就是可能是架构问题,比如没有分布式处理,无法动态扩容,基本上你需要查看内存,CPU,磁盘使用情况,使用top,free ,df等命令来动态查看找到异常指标的进程

                 2. 如果DLL 将静态作用域数据声明为 __declspec(thread),则在显式链接时 DLL会导致保护错误。用 LoadLibrary 加载 DLL 后,每当代码引用此数据时 DLL 就会导致保护错误。(静态作用域数据既包括全局静态项,也包括局部静态项。)因此,创建DLL 时应避免使用线程本地存储区,或者应(在用户尝试动态加载时)告诉 DLL 用户潜在的缺陷。

    展开全文
  • Linux下的动态链接库的制作使用方法,完全是根据个人理解经验总结,有不对的地方还请大家指正。动态链接库的生成:代码上与写静态链接库没什么区别,主要是在编译时,以两个文件举例:/*mylib.h*/void Print();/...

    Linux下的动态链接库的制作和使用方法,完全是根据个人理解和经验总结,有不对的地方还请大家指正。

    动态链接库的生成:

    代码上与写静态链接库没什么区别,主要是在编译时,以两个文件举例:

    /*mylib.h*/

    void Print();

    /*mylib.c*/

    #include

    #include "mylib.h"

    void Print()

    {

    printf("This is in mylibn");

    }

    编译方法如下:

    gcc -fpic -shared mylib.c -o mylib.so

    此时将生成mylib.so动态链接库文件。

    动态链接库在使用时,分为“隐式调用”和“显式调用”两种:

    1.如果是隐式调用,则与静态库的使用方法差不多,注意需要包含导出函数的头文件,即mylib.h:

    #include ...

    #include "mylib.h"

    int main()

    {

    Print();

    }

    编译方法:

    gcc -o main main.c -L./ mylib.so

    注意要加上动态链接库的搜索路径,否则编译器只会到系统路径中去寻找。

    2.显式调用的方式,不必包含mylib.h,但是需要增加几个系统调用:

    #include ...

    #include  // 显式加载需要用到的头文件

    int main()

    {

    void *pdlHandle = dlopen("./mylib.so", RTLD_LAZY); // RTLD_LAZY 延迟加载

    char *pszErr = dlerror();

    if( !pdlHandle || pszErr )

    {

    printf("Load mylib failed!n")

    return 1;

    }

    void (*Print)() = dlsym(pdlHandle, "Print"); // 定位动态链接库中的函数

    if( !Print )

    {

    pszErr = dlerror();

    printf("Find symbol failed!%sn", pszErr);

    dlclose(pdlHandle);

    return 1;

    }

    Print(); // 调用动态链接库中的函数

    dlclose(pdlHandle); // 系统动态链接库引用数减1

    return 0;

    }

    可以看到,显式调用的代码看上去要复杂很多,但是却比隐式调用要灵活,我们不必在编译时就确定要加载哪个动态链接库,可以在运行时再确定,甚至重新加载。

    看一下显式调用的编译方式:

    gcc -ldl -o main main.c

    注意要添加-ldl选项,以使用显式调用相关的函数调用

    手动加载动态链接库dlopen dlsym dlcolose

    1.  打开动态链接库:

    #include

    void *dlopen(const char *filename, int flag);

    该函数返回操作句柄,如:

    void *pHandle = dlopen(strSoFilePath, RTLD_LAZY);

    2.  取动态对象地址:

    #include

    void *dlsym(void *pHandle, char *symbol);

    dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。

    使用这个函数不但可以获取函数地址,也可以获取变量地址。比如,假设在so中

    定义了一个void mytest()函数,那在使用so时先声明一个函数指针:

    void (*pMytest)(),然后使用dlsym函数将函数指针pMytest指向mytest函数,

    pMytest = (void (*)())dlsym(pHandle, "mytest");

    3.  关闭动态链接库:

    #include

    int dlclose(void *handle);

    该函数将该.so的引用计数减一,当引用计数为0时,将它从系统中卸载。

    4.  动态库错误函数:

    #include

    const char *dlerror(void);

    当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时   表示没有错误信息。

    在取到函数执行地址后,就可以在动态库的使用程序里根据动态库提供的函数接口调用动态库里的函数。在编写调用动态库的程序的Makefile文件时,需要加入编译选-ldl。

    从void *dlsym(void *handle, char *symbol); 的参数可以看出,该函数只传两个参数:一个指向so的handle和一个函数的symbol,所以so里面的函数应该不允许重,否则根据一个symbol不能确定指向那个函数。

    展开全文
  • 动态调用即显示链接,静态调用即隐式链接。 动态链接库(Dynamic Linked Library)缩写就是将一些api函数写入到一个dll文件中,在程序在程序运行时再加载到程序的进程空间中使用,这样可以让运行程序本身体积较小,...

    动态调用即显示链接,静态调用即隐式链接。

    动态链接库(Dynamic Linked Library)缩写就是将一些api函数写入到一个dll文件中,在程序在程序运行时再加载到程序的进程空间中使用,这样可以让运行程序本身体积较小,方便模块化编程。后缀名一般是.dll。

    静态链接库(StaticLibrary)和动态链接库作用基本相同但是静态链接库在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件),所以组成的exe文件体积较大,静态链接库后缀名一般为.lib。

    Import导入库就综合了两种库包含两种文件.dll和.lib文件,.dll文件和上面的动态链接库相同,包含导出函数和数据等,但这里的.lib文件就和静态链接库有所不同,这里的.lib文件只是包含一些被DLL导出的函数和变量的符号名,一般称这个lib文件为引入库。

    现在,开始编写一个dll,选择win32,然后win32控制台程序,选择DLL,然后在文件名.cpp中写下代码:

    // testDLL.cpp : 定义 DLL 应用程序的导出函数。
    
    #include "stdafx.h"//这里保存的是DLL的导出函数
    extern "C" __declspec(dllexport) int add(int a, int b) 
    {
        return (a + b);
    }
    
    extern "C" __declspec(dllexport) int sub(int a, int b)
    {
        return (a - b);
    }
    extern "C" __declspec(dllexport) int msg()
    {
    	MessageBox(NULL,TEXT("第一个dll程序"),TEXT("MY"),MB_OK);
        return 0;
    }
    
    
    

    通过上面的代码编译在Debug中,可以得到一个testDLL.lib文件和一个testDLL.dll文件。然后在写程序来调用这个dll。

    隐式链接:
    实现一个简单的隐式链接,需要将生成的lib文件放入loadDLL工程文件夹下面,并设置编译器的附加依赖项中增加此lib(也可以直接在代码中增加使用语句如#pragma comment(lib,"testDLL.lib"))

    #include <iostream>
    #include <windows.h>
    
    #pragma comment(lib,"testDLL.lib")
    extern "C"_declspec(dllimport) int add(int a, int b);
    extern "C"_declspec(dllimport) int sub(int a, int b);
    extern "C"_declspec(dllimport) int msg();
    int main()
    {
        int a = 9;
        int b = 3;
        int nAdd = add(a, b);
        int nSub = sub(a, b);
        std::cout << nAdd << ":" << nSub << std::endl;
    	msg();
        system("pause");
        return 0;
    }

    显示链接:

    显示链接只需要生成的一个dll文件就能使用了,但是使用较为复杂需要用到指针函数及LoadLibrary等相关知识。在使用dll中的函数时我们首先需要使用导入函数将dll文件导入到进程地址空间再使用GetProcAddress得到dll中的函数地址再使用。

    #include <iostream>
    #include <windows.h>
    
    int main()
    {
        typedef int (*_pAdd)(int a, int b);
        typedef int (*_pSub)(int a, int b);
    	typedef int (*_pmsg)();
        HINSTANCE hDll = LoadLibrary(TEXT("testDLL.dll"));
        int nParam1 = 9;
        int nParam2 = 3;
        _pAdd pAdd = (_pAdd)GetProcAddress(hDll, "add");
        _pSub pSub = (_pSub)GetProcAddress(hDll, "sub");
    	 _pmsg pmsg = (_pmsg)GetProcAddress(hDll, "msg");
        int nAdd = pAdd(nParam1, nParam2);
        int nSub = pSub(nParam1, nParam2);
        pmsg();
        std::cout << nAdd << ":" << nSub << std::endl;
        FreeLibrary(hDll);
        system("pause");
        return 0;
    }

     

    展开全文
  • 隐式链接指将DLL的函数符号输出库LIB链接,在执行文件中IMPORT段加入一系列函数的入口点!程序在加载启动时自动加载这些DLL,并查找函数入口点!像普通的SDK程序要加入KERNEL32。LIB链接就是!这样的方法是当使用DLL...
  • 显示链接 隐式链接

    千次阅读 2007-06-24 14:27:00
    显示连接指知道函数的原型,定义一个函数指针后,用LoadLibraryGetProcAddress函数取函数的地址的方法。隐式链接指已经包含了函数的.h文件,直接引用函数,在连接的时候将.lib文件连接进去。隐式链接后,exe程序一...
  • 使用动态DLL有两种方法,一种是隐式链接,一种是显式链接,如果用loadlibrary就是显示链接,用lib就属于隐式链接。 两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样的。显式调用麻烦了...
  • 最近需要在程序中调用DLL,因为之前没调用过,对这个不是很清楚,对显示加载和隐式加载简单说明一下。 两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样的。显式调用麻烦了点,但可以...
  • 显示链接和隐式链接区别在于复制的代码量不同,后文会讲; 上文符号重复就是因为 DynamicA.framework 自身包含了 FMDB,在 Link 时,正好被复制的 StaticB.framework 的代码也包含 FMDB ,因此就发生了符号表重复;...
  • sql隐式连接和显示链接 In SQL Server, it`s not always required to fully understand the internal structure, especially for performance and optimization, if the database design is good, because SQL ...
  • 隐式调用,使用起来比较 简单,有函数的声明(头文件.h)就可以了,但必须有lib库。 在VC中两种方式的具体方法: 一、动态库的隐示调用: 在 VC 工程中直接链接静态输入库XXX.lib,然后即可像调用其它源文件中 的...
  • 创建useDll工程,隐式动态链接:将dll工程编译好后的复制到useDll工程根目录下,然后使用如下代码 1 #include 2 #include " CustomDll.h " 3 #include 4 using namespace std; 5 #pragma ...
  • 自己学习QT中DLL显示加载和隐式加载的Demo,相关文章链接:https://www.jianshu.com/p/2851c0f7f4a9
  • C++程序在运行时有两种方式加载动态连接库:隐式链接和显式链接。 加载动态库文件就是将动态库中的代码逻辑映射到用户进程地址空间,就在程序执行的时候进行函数调用。 隐式链接 隐式链接是在程序开始执行时就将动态...
  • 1.显示调用时需要什么文件及放在什么地方,调用方式举例。  需要.dll文件.h文件  .h放在调用程序项目目录下,与debug文件平行;.dll放在解决方案的debug文件中  实例:  typedef void (*lpFun)(void); ...
  • DLL系列---Dll的隐式链接和显示链接

    千次阅读 2014-11-09 16:07:33
    DLL系列---Dll的隐式链接和显示链接 一. 首先我们需要明确几个关于DLL概念 显示链接隐式链接,动态调用、静态调用,动态链接库、静态链接库、Import导入库。 动态调用即显示链接,静态调用即隐式链接,在...
  • Windows10 64位系统,VS2013 编程平台...工程二为调用DLL的方法,分为隐式调用显式调用。两个工程都是控制台应用程序consoleapplication。 对应的文章为 https://blog.csdn.net/u012210613/article/details/88904841
  • 显示连接指知道函数的原型,定义一个函数指针后,用LoadLibraryGetProcAddress函数取函数的地址的方法。隐式链接指已经包含了函数的.h文件,直接引用函数,在连接的时候将.lib文件连接进去。隐式链接后,exe程序一...

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 274
精华内容 109
关键字:

显示链接和隐式链接