调用时有什么区别?

解决方案 »

  1.   

    你可以这样理解,lib相当于头文件.h,dll相当于.cpp
      

  2.   

    这个说起来有点多。首先LIB有两种。静态库和动态库都有LIB文件。
    静态库的LIB文件里面就是代码,在链接时这些代码会链接到EXE文件中,编译链接成功后,LIB文件就不用了。一般像CRT库都是以这种LIB文件的形式提供的。动态库也有LIB文件,不过和静态库不同,动态库的代码是放在DLL文件中的,LIB文件中只是一些链接时用到的信息。在隐式调用DLL文件时,必须要加上#pragma comment(lib,"MyDll");或者在编译器中设置LIB文件名链接才能成功。
    如果是显式调用DLL,因为用LoadLibrary和GetProceAddress定位函数,所以不用LIB文件。
    不管是显式调用还是隐式调用,LIB文件在编译链接好后都不需要了。而DLL文件在执行时还是必须的。
      

  3.   

    同意楼上的, 如果是静态库的LIB文件的话就不需要DLL了.但是还都需要包含.H头文件.
    显式调用DLL的时候可以不包含头文件,但是你需要知道接口函数名的信息,在GetProceAddress定位函数时用到.不知道我补充的对不对.
      

  4.   

    不错,不过,我还是比较喜欢静态链接LIB,没有多余的dll,只有自己的程序
      

  5.   

    lib有静态lib和动态lib之分。
      静态lib将导出声明和实现都放在lib中。编译后所有代码都嵌入到宿主程序
      动态lib相当于一个h文件,是对实现部分(.dll文件)的导出部分的声明。编译后只是将导出声明部分编译到宿主程序中,运行时候需要相应的dll文件支持动态链接库(DLL) 是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数
    楼主明白了否?
      

  6.   

    简而言之,lib是在编译时候用
    dll是在运行时候用
    比如做成产品后,都是用dll打包进去,然后安装,在别的机器上就可以用了
      

  7.   


    补充一下: 静态lib直接调用,不需要再用dll
    动态lib 
    若显式调用 需要lib dll  lib相当于dll中函数的符号导出表 指示函数地址等 信息
    若隐式调用 不需要lib 直接dll GetProceAddress定位函数
      

  8.   

      许多单讲C++的书其实都过于学院派,对于真实的工作环境,上百个源文件怎么结合起来,几乎没有提及。我引导读者一步步看看lib与DLL是怎么回事。 
    一个最简单的C++程序,只需要一个源文件,这个源文件包含了如下语句 
    int main(){return 0;} 
    自然,这个程序什么也不做。 当需程序需要做事情时,我们会把越来越多的语句添加到源文件中,例如,我们会开始在main函数中添加代码: 
    #include <stdio.h> 
    int main() 

    printf("Hello World!\n"); 
    return 0; 

    由于人的智力水平的限制,当一个函数中包含了太多的语句时,便不太容易被理解,这时候开始需要子函数: 
    #include <stdio.h> 
    void ShowHello() 

    printf("Hello World!\n"); 

    int main() 

    ShowHello(); 
    return 0; 

    同样的道理,一个源文件中包含了太多的函数,同样不好理解,人们开始分多个源文件了 
    // main.cpp 
    void ShowHello();//[1] 
    int main() 

    ShowHello(); 
    return 0; 

    // hello.cpp 
    #include <stdio.h> 
    void ShowHello() 

    printf("Hello World!\n"); 

    将这两个文件加入到一个VC工程中,它们会被分别编译,最后链接在一起。在VC编译器的输出窗口,你可以看到如下信息 
    --------------------Configuration: hello - Win32 Debug-------------------- 
    Compiling... 
    main.cpp 
    hello.cpp 
    Linking...  
    hello.exe - 0 error(s), 0 warning(s) 
    这展示了它们的编译链接过程。 
    接下来,大家就算不知道也该猜到,当一个工程中有太多的源文件时,它也不好理解,于是,人们想到了一种手段:将一部分源文件预先编译成库文件,也即lib文件,当要使用其中的函数时,只需要链接lib文件就可以了,而不用再理会最初的源文件。 
    在VC中新建一个static library类型的工程,加入hello.cpp文件,然后编译,就生成了lib文件,假设文件名为hello.lib。 
    别的工程要使用这个lib有两种方式: 
    1 在工程选项-〉link-〉Object/Library Module中加入hello.lib 
    2 可以在源代码中加入一行指令 
    #pragma comment(lib, "hello.lib") 
    注意这个不是C++语言的一部分,而是编译器的预处理指令,用于通知编译器需要链接hello.lib 
    根据个人爱好任意使用一种方式既可。 
           这种lib文件的格式可以简单的介绍一下,它实际上是任意个obj文件的集合。obj文件则是cpp文件编译生成的,在本例中,lib文件只包含了一个obj文件,如果有多个cpp文件则会编译生成多个obj文件,从而生成的lib文件中也包含了多个obj,注意,这里仅仅是集合而已,不涉及到link,所以,在编译这种静态库工程时,你根本不会遇到链接错误。即使有错,错误也只会在使用这个lib的EXE或者DLL工程中暴露出来。 
    关于静态lib,就只有这么多内容了,真的很简单,现在我们介绍另外一种类型的lib,它不是obj文件的集合,即里面不含有实际的实现,它只是提供动态链接到DLL所需要的信息。这种lib可以在编译一个DLL工程时由编译器生成。涉及到DLL,问题开始复杂起来,我不指望在本文中能把DLL的原理说清楚,这不是本文的目标,我介绍操作层面的东西。 
    简单的说,一个DLL工程和一个EXE工程的差别有两点: 
    1 EXE的入口函数是main或者WinMain,而DLL的入口函数是DllMain 
    2 EXE的入口函数标志着一段处理流程的开始,函数退出后,流程处理就结束了,而DLL的入口函数对系统来说,只是路过,加载DLL的时候路过一次,卸载DLL的时候又路过一次[2],你可以在DLL入口函数中做流程处理,但这通常不是DLL的目的,DLL的目的是要导出函数供其它DLL或EXE使用。你可以把DLL和EXE的关系理解成前面的main.cpp和hello.cpp的关系,有类似,实现手段不同罢了。 
    先看如何写一个DLL以及如何导出函数,读者应该先尝试用VC创建一个新的动态链接库工程,创建时选项不选空工程就可以了,这样你能得到一个示例,以便开始在这个例子基础上工作。 
    看看你创建的例子中的头文件有类似这样的语句: 
    #ifdef DLL_EXPORTS 
    #define DLL_API __declspec(dllexport) 
    #else 
    #define DLL_API __declspec(dllimport) 
    #endif 
     这就是函数的导出与使用导出函数的全部奥妙了。你的DLL工程已经在工程设置中定义了一个宏DLL_EXPORTS,因此你的函数声明只要前面加DLL_API就表示把它导出,而DLL的使用者由于没有定义这个宏,所以它包含这个头文件时把你的函数看作导入的。通过模仿这个例子,你就可以写一系列的标记为导出的函数了。 
            导出函数还有另一种方法,是使用DEF文件,DEF文件的作用,在现在来说只是起到限定导出函数名字的作用,这里,我们要引出第二种[4]使用DLL的方法:称为显示加载,通过Windows API的LoadLibrary和GetProcAddress这两个函数来实现[5],这里GetProcAddress的参数需要一个字符串形式的函数名称,如果DLL工程中没有使用DEF文件,那么很可能你要使用非常奇怪的函数名称(形如:?fnDll@@YAHXZ)才能正确调用,这是因为C++中的函数重载机制把函数名字重新编码了,如果使用DEF文件,你可以显式指定没编码前的函数名。
          有了这些知识,你可以开始写一些简单的DLL的应用,但是我可以百分之百的肯定,你会遇到崩溃,而之前的非DLL的版本则没有问题。假如你通过显式加载来使用DLL,有可能会是调用约定不一致而引起崩溃,所谓调用约定就是函数声明前面加上__stdcall __cdecl等等限定词,注意一些宏如WINAPI会定义成这些限定词之一,不理解他们没关系,但是记住一定要保持一致,即声明和定义时一致,这在用隐式加载时不成问题,但是显示加载由于没有利用头文件,就有可能产生不一致。 调用约定并不是我真正要说的,虽然它是一种可能。我要说的是内存分配与释放的问题。请看下面代码: 
    void foo(string& str) 

    str = "hello"; 

    int main() 

    string str; 
    foo(str); 
    printf("%s\n", str.c_str()); 
    return 0; 

    当函数foo和main在同一个工程中,或者foo在静态库中时,不会有问题,但是如果foo是一个DLL的导出函数时,请不要这么写,它有可能会导致崩溃[6]。崩溃的原因在于“一个模块中分配的内存在另一个模块中释放”,DLL与EXE分属两个模块,例子中foo里面赋值操作导致了内存分配,而main中return语句之后,string对象析构引起内存释放。 
    我不想穷举全部的这类情况,只请大家在设计DLL接口时考虑清楚内存的分配释放问题,请遵循谁分配,谁释放的原则来进行。 
    如果不知道该怎么设计,请抄袭我们常见的DLL接口--微软的API的做法,如: 
    CreateDC 
    ReleaseDC 
    的成对调用,一个函数分配了内存,另外一个函数用来释放内存。 
    回到我们有可能崩溃的例子中来,怎么修改才能避免呢? 
    这可以做为一个练习让读者来做,这个练习用的时间也许会比较长,如果你做好了,那么你差不多就出师了。一时想不到也不用急,我至少见过两个有五年以上经验的程序员依然犯这样的错误。 注[1]:为了说明的需要,我这里使用直接声明的方式,实际工程中是应该使用头文件的。 
    注[2]: 还有线程创建与销毁也会路过DLL的入口,但是这对新手来说意义不大。 
    注[3]:DEF文件格式很简单,关于DEF文件的例子,可以通过新建一个ATL COM工程看到。 
    注[4]:第一种方法和使用静态库差不多,包含头文件,链接库文件,然后就像是使用普通函数一样,称为隐式加载。 
    注[5]:具体调用方法请参阅MSDN。 
    注[6]:之所以说有可能是因为,如果两个工程的设置都是采用动态连接到运行库,那么分配释放其实都在运行库的DLL中进行,那么这种情况便不会发生崩溃 
    帮楼主找的 看看 我以前也是看过这个