经常使用到第三方库。比如:glut,freetype,sdl,大一点的有CEGUI,OSG等。
这些库虽然是开源的,但是很多时候只是使用他们,一般不会去修改。
使用就会涉及到三个东西:.h .lib .dll文件。
主要有三种模式:
.h+.lib
.h+.lib+.dll
.dll
第二种是最常见的,其他两种都比较少
一,下面自己实现一个dll和lib:
英文链接网址:http://msdn.microsoft.com/en-us/library/ms235636(VS.80).aspx
注意我的编译器是vs2005。
1,建立一个win32控制台应用程序, 输入工程名字后点击确定 点击下一步, 选择应用程序类型: DLL 附加选项选择:空项目 。点击确定
2,在空的工程中添加头文件MathFuncsDll.h ,内容如下:
- // MathFuncsDll.h
- namespace MathFuncs
- {
- class MyMathFuncs
- {
- public:
- // Returns a + b
- static __declspec(dllexport) double Add(double a, double b);
- // Returns a - b
- static __declspec(dllexport) double Subtract(double a, double b);
- // Returns a * b
- static __declspec(dllexport) double Multiply(double a, double b);
- // Returns a / b
- // Throws DivideByZeroException if b is 0
- static __declspec(dllexport) double Divide(double a, double b);
- };
- }
3,添加MathFuncsDll.cpp文件内容如下:
- // MathFuncsDll.cpp
- // compile with: /EHsc /LD
- #include "MathFuncsDll.h"
- #include <stdexcept>
- using namespace std;
- namespace MathFuncs
- {
- double MyMathFuncs::Add(double a, double b)
- {
- return a + b;
- }
- double MyMathFuncs::Subtract(double a, double b)
- {
- return a - b;
- }
- double MyMathFuncs::Multiply(double a, double b)
- {
- return a * b;
- }
- double MyMathFuncs::Divide(double a, double b)
- {
- if (b == 0)
- {
- throw new invalid_argument("b cannot be zero!");
- }
- return a / b;
- }
- }
4, 设置工程属性:
左边解决方案资源管理器中右击工程名:弹出的对话框中:左边,配置属性:/常规 下: 右边 配置类型:选择动态库(.dll)
然后点击生成:/ 生成 MathFuncDll。
此时可以到debug文件夹下去查看一下: MathFuncsDll.dll MathFuncsDll.lib 这两个文件是我们最关心的。注意此时的MathFuncsDll.lib文件只有3kb大
二,使用dll和lib文件
新建一个空的win32控制台应用程序:UseMathDll项目名字
添加cpp文件MyExecRefsDll.cpp:
- #include <iostream>
- #include "MathFuncsDll.h"
- #pragma comment(lib , "MathFuncsDll.lib") //导入lib文件
- using namespace std;
- int main()
- {
- double a = 7.4;
- int b = 99;
- cout << "a + b = " <<
- MathFuncs::MyMathFuncs::Add(a, b) << endl;
- cout << "a - b = " <<
- MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
- cout << "a * b = " <<
- MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
- cout << "a / b = " <<
- MathFuncs::MyMathFuncs::Divide(a, b) << endl;
- system("PAUSE");
- return 0;
- }
然后将MathFuncsDll.lib 和 MathFuncsDll.h文件 放到和MyExecRefsDll.cpp一个文件目录下,也就是当前目录下。将MathFuncsDll.dll可以放到system32下,当然了最简单的做法就是放到UseMathDll这个工程的debug或者release文件夹里面,将来生成的exe就可以直接在当前目录下找到需要的dll文件。(动态链接文件,如果不把dll放入system32或者debug中,会导致程序无法运行。因为真正的函数的可执行代码都在dll中。lib文件仅仅只是一个索引,而.h文件仅仅只给出了一个借口而已。)
此时就可以点击运行了:
结果如下:
- a + b = 106.4
- a - b = -91.6
- a * b = 732.6
- a / b = 0.0747475
- 请按任意键继续. . .
三,直接使用.h 和 lib文件
还是打开MathFuncsDll工程项目,依照条目一中的设置工程属性:不过最后的配置类型 选择静态库(.lib)
然后生成MathFuncsDll,然后到debug下面看一下,此时的MathFuncsDll.lib文件变成了29k
然后把MathFuncsDll.lib替换掉UseMathDll工程目录下的原来的MathFuncsDll.ib文件,而且把Debug下的MathFuncsDll.dll删掉,UseMathDll照样正常运行。
下面是dll与lib的详细对比:
.h头文件是编译时必须的,lib是链接时需要的,dll是运行时需要的。
附加依赖项的是.lib不是.dll,若生成了DLL,则肯定也生成 LIB文件。如果要完成源代码的编译和链接,有头文件和lib就够了。如果也使动态连接的程序运行起来,有dll就够了。在开发和调试阶段,当然最好都有。
.h .lib .dll三者的关系是:
H文件作用是:声明函数接口
DLL文件作用是: 函数可执行代码
当我们在自己的程序中引用了一个H文件里的函数,编链器怎么知道该调用哪个DLL文件呢?这就是LIB文件的作用: 告诉链接器 调用的函数在哪个DLL中,函数执行代码在DLL中的什么位置,这也就是为什么需要附加依赖项 .LIB文件,它起到桥梁的作用。如果生成静态库文件,则没有DLL ,只有lib,这时函数可执行代码部分也在lib文件中
目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。动态库一般会有对应的导入库,方便程序静态载入动态链接库,否则你可能就需要自己LoadLibary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。在动态库的情况下,有两个文件,而一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。
-------------------------------------------------------------------------------------
静态链接库(Lib)与动态链接库(DLL)的区别
静态链接库(Lib)
在VC++6.0中new一个名称为libTest的static library工程,
并新建lib.h和lib.cpp两个文件,lib.h和lib.cpp的源代码如下:
//文件:lib.h
#ifndef LIB_H
#define LIB_H
extern "C" int add(int x,int y); //声明为C编译、连接方式的外部函数
#endif
//文件:lib.cpp
#include "lib.h"
int add(int x,int y)
{
return x + y;
}
编译这个工程就得到了一个.lib文件,这个文件就是一个函数库,它提供了add的功能。将头文件和.lib文件提交给用户后,用户就可以直接使用其中的add函数了。
标准Turbo C2.0中的C库函数(我们用来的scanf、printf、memcpy、strcpy等)就来自这种静态库。
#include <stdio.h>
#include "..\lib.h"//不可丢失
#pragma comment( lib, "..\\debug\\libTest.lib" ) //指定与静态库一起连接
int main(int argc, char* argv[])
{
}
静态链接库的调用就是这么简单,或许我们每天都在用,可是我们没有明白这个概念。代码中#pragma comment( lib , "..\\debug\\libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接