Days in DLL(一)

1,  静态库与动态库的区别:

      最显著的区别是:  静态库 生成EXE文件后可以遗弃,  动态库却要一直跟随。


      静态库的原理是: 在编译链接可执行文件(exe)时, 链接器将库中的函数与数据 与应用程序的其他模块组合起来, (这里我看作是inline 或是 insert)

      动态库的原理是: 首先动态库也有类似静态库的文件(lib)(确实让人费解, 这里我们称之引入库文件, 不知大家记得函数申明吗? 所谓的申明在h文件, 实现在cpp文件?这里就是答案了。 这里的引入库文件充当的就是h文件的角色。在编译的时候跟静态库的原理相似, lib文件组合入应用程序中, 而dll仍在外部。这也是为什么生成EXE文件后动态库一直跟随的原因)


    其实在上面已经道出动态链接库的优势所在。。。。(plug and play?)当我们想要更改程序里面的某一个函数的实现, easy, 只需改变其dll。还有, 这里就意味着分工合作实现的可能性,  每个人只需为自己的dll文件负责。。。更多详细内容,请百度, 这里就不多累赘了。


2, 简单制作dll && 使用之:

      制作dll,  

            本人用的是VS2013, 新建 控制台项目 下一步 选择dll  空项目, 下面是其代码:

MyDll.cpp

int sharenum = 0;


__declspec(dllexport) int add(int a, int b)
{
	return a + b;
}

__declspec(dllexport) double add(double a, double b)
{
	return a + b;
}


__declspec(dllexport) int minus(int a, int b)
{
	return a - b;
}

__declspec(dllexport) int shareNum()
{
	return sharenum;
}

__declspec(dllexport) int sharenumplus(int num)
{
	sharenum += num;
	return shareNum();
}


    使用dll: 

      正如我上面(第一节所言, 编译需要lib 以及dll文件, 在本工程Debug中, 复制其lib  dll。)下面是使用的代码:

testDll.cpp


#include "stdio.h"

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

_declspec(dllimport) int add(int a, int b);
extern int minus(int a, int b);
extern int shareNum();
extern int sharenumplus(int num);
int main()
{
	printf("1 + 2 = %d\n", add(1, 2));
	printf("1 - 2 = %d\n", minus(1, 2));
	printf("shareNum is %d\n", shareNum());
	char ch;
	scanf("%c", &ch);
	printf("shareNum + 1 is %d\n", sharenumplus(1));
	scanf("%c", &ch);
	return 0;
}


温馨提示:

注1: ConsoleApplication1.lib 因为我上一个工程的名称为之,这里值得注意的是 _declspec(dllimport) 与 extern (顺道说一下上文的_declspec(dllexport), 它表示该方法可以被其他程序所调用,maybe private ->>>   public?), 回到正题, 这俩者的效果是一致的, 也就是声明外部调用的方法, 不同的是:_declspec(dllimport)更高效。

注2:更为常见的是:头文件定义好所有函数, 源文件实现, 这里用一个技巧:

//h文件:
#ifndef DLL1_API
#define DLL1_API _declspec(dllimport)
#endif // !DLL1_API
DLL1_API int add(int a, int b);
。。。。。。


//cpp:
#define DLL1_API _declspec(dllexport)
#include "dllHeader.h"
int add(int a, int b)
{
	return a + b;
}
。。。

这里有个好处, 即:可以有一个类似doc的文件(h文件)可以参考,方便使用者。 当然最显著的特点是, 使用dll的时候, 只需加载lib, 函数申明可以用#include头文件解决。

#include "dllHeader.h"
#include "stdio.h"
#pragma comment (lib, "MyDll.lib")
int main()
{
	printf("1 + 2 = %d\n", add(1,2));
	char ch;
	scanf("%c", &ch);
}

 

3, 从DLL中导出类:

   基本格式:

  

//**.h
class DLL1_API robot{
public :
	void sayhello();
};

//**.cpp
void robot::sayhello()
{
	printf("hello world");
}
//关于DLL1_API, 请看上文温馨2

不知读者是否知道 transient,  这个是在序列化里面的(Java), 所修饰的数据将不参与序列化过程。

而这里的_declspec(export) 是否有异曲同工之妙呢? 只有用这个修饰的才能从dll 中导出。



4. 解决名字改编问题:

问题描述:

编译器在生成dll文件的时候, 会对其名字进行改编,   不同编译器, 改编的形式或许有所不同, 这就有可能发生A编译生成的dll, B不能使用的情况。

(2015/04/22 其原因是:C 中没有重载的概念,而C++有,也就是说,C++编译生成名字的时候,会加上其参数列表的内容,测试代码如下:)

//override.c
#include "stdio.h"
int hello(int a)  
{
        printf("arg is %d\n", a); 
        return 0;
}
int hello()
{
        printf("no arg");
        return 0;
}
int main() 
{
        
        return 0;
}

结果:

插播一下(其实命名很重要,一个好的文件,函数,字段名字是无需额外的注解的,所以学好英语很重要  ovo    请忽略我,我一般百度翻译。。)

解决方法:

方法一:
添加限定符:       extern “C”    // C必须是大写的。表示用C编译器编译 
函数调用约定:    _stdcall   

即为:
//h文件:
#ifndef DLL1_API
#define DLL1_API <strong>extern "C" </strong>_declspec(dllimport)
#endif // !DLL1_API
DLL1_API int  <strong>_stdcall</strong>  add(int a, int b);
。。。。。。


//cpp:
#define DLL1_API<strong> <span style="font-family: Arial, Helvetica, sans-serif;">extern "C"</span></strong><span style="font-family: Arial, Helvetica, sans-serif;"><strong> </strong>_declspec(dllexport)</span>
#include "dllHeader.h"
int  <strong>_stdcall</strong>  add(int a, int b)
{
	return a + b;
}
。。。

缺点:  不支持class, 不允许重载函数的第二个 C 链接(我理解为 不允许函数重载, 即函数不能同名)


方法二: 使用模块定义文件DEF

1, 在dll工程中添加def文件
2, 编写def文件

LIBRARY MyDll

EXPORTS
add                          //sample1
myminus= minus     //sample2
sample1:     表示源文件中定义的add 将以 add 符号名导出。
sample2:     表示源文件中定义的minus将以myminus符号名导出。(使用时, 需要改动h文件即可)

使用dumpbin一查,   发现如下情况:

<strong>1    0 00011109 add = @ILT+260(_add@8)
2    1 00011005 minus = @ILT+0(_minus)
3    2 00011005 myminus = @ILT+0(_minus)</strong>

恩, 看样子,   这是别名。。。。。。。。。不过经检验, 确实可以用myminus调用其函数

而且   看样子, 这个不能解决函数重载的问题


结语:

这里是我的一人之言, 总有疏漏, 欢迎打脸。。。微笑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值