extern "C"的简单解析         我们前面介绍了显式调用dll的方法,例如



http://www.cnblogs.com/laogao/archive/2012/12/07/2806528.html ,其中在GetProcAddress第二个参数的填写煞费苦心,我们需要比较麻烦地使用vs自带的dumpbin查看dll的具体函数,即使后来可以使用MAKEINTRESOURCE直接填写函数序号来不直接填写函数名,依然你需要在dumpbin中查找函数的序号,比较费力。

其实我们有更好的方法来解决这个问题,其中一个比较好的一个方法是改用extern "C"来修饰函数,使之按照c的风格来编译函数。我们知道c不支持函数重载,因此我们定义的时候用的什么名字,在显式调用dll的时候也是用的这个名字,完全不用改变,很简单。

在进行下面的介绍之前,先可以阅读这个文章《extern "C"的简单解析》

下面我们介绍两个例子。

例1. 在纯C++环境下使用c语言方式编译dll,然后调用

      CreateDLL.h

<span style="color:#000000;">// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 CREATEDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// CREATEDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef CREATEDLL_EXPORTS
#define CREATEDLL_API __declspec(dllexport)
#else
#define CREATEDLL_API __declspec(dllimport)
#endif#ifdef __cplusplus
extern "C"
{
#endifCREATEDLL_API void printMax(int&, int&);
#ifdef __cplusplus
}
#endif // __cplusplus
</span>
// CreateDLL.cpp : 定义 DLL 应用程序的导出函数。
//#include "stdafx.h"
#include "CreateDLL.h"
#include <iostream>CREATEDLL_API void printMax(int& a, int& b)
{std::cout << "Among (" << a << "," << b << "), the Max Number is " << (a > b ? a : b) << "\n";
}

然后点击“生成”,即可生成dll和lib。接下来我们就可以直接使用了。注意:生成dll的时候,需要先设置dll的项目为启动项。当使用dll的时候,需设置使用dll的项目为启动项。

先看显式调用:

#include <Windows.h>
#include <iostream>typedef void(*FUNA)(int&, int&);int main()
{const char* dllName = "CreateDLL.dll";int x(100), y(100);HMODULE hDLL = LoadLibrary(dllName);if (hDLL!=NULL){FUNA fp1 = FUNA(GetProcAddress(hDLL, "printMax"));if (fp1!=NULL){std::cout << "Input 2 Numbers:";std::cin >> x >> y;fp1(x, y);}else{std::cout << "connot find the function "<<"printMax" << std::endl;}FreeLibrary(hDLL);}else{std::cout << "cannot load dll"<<dllName << std::endl;}system("pause");return 0;}

注意观察,我们的GetProcAddress的第二个参数直接使用原来的函数名。另外需要注意的是在使用dll的项目中,我们没有包含dll的头文件,但是仍然可以使用。但是有时候也过不去,此时你需要包含dll的.h的路径。

再看隐式调用:

#include "CreateDLL.h"
#include <iostream>
using namespace std;#pragma  comment(lib,"CreateDLL.lib")int main()
{int a,b;cout << "input 2 num:";cin >> a >> b;printMax(a,b);system("pause");return 0;
}

将.h,.lib,.dll一块儿放在项目目录下,然后在程序中使用#pragma comment(lib,"CreateDLL.lib"),即可成功链接dll。与显式调用,隐式调用比较简单。

另外在上一篇《c++显式加载dll并使用DLL的类》 ,我们也使用了extern "C"的风格

extern "C" INTERFACE_API Interface* Export(void); 

例2. 在纯C环境下使用c语言方式编译dll,然后在C++中调用
    CreateDLL.h

//c.h
#ifndef _C_H_
#define _C_H_   //防止被重复包含#ifdef CREATEDLL_EXPORTS
#define CREATEDLL_API __declspec(dllexport)
#else
#define  CREATEDLL_API __declspec(dllimport)
#endif#ifdef __cplusplus
extern "C" {
#endifextern  CREATEDLL_API int add(int x, int y);#ifdef __cplusplus
}
#endif#endif

CreateDLL.c

#include "CreateDLL.h"
int add(int x, int y)
{return x + y;
}

然后我们就可以生成dll了。注意我们这里都是c语言。

然后我们在c++中调用dll。

显式调用:

#include <Windows.h>
#include <iostream>
#include "CreateDLL.h"typedef int(*Func)(int, int);#pragma  comment(lib,"CreateDLL.lib")int main()
{HMODULE Hdll = LoadLibrary("CreateDLL.dll");if (Hdll!=nullptr){Func f = Func(GetProcAddress(Hdll, "add"));if (f!=nullptr){std::cout << "input 2 num:";int a, b;std::cin >> a >> b;std::cout << "result is " << add(a, b);}else{std::cout << "connot find the function " << "add" << std::endl;}FreeLibrary(Hdll);}else{std::cout << "cannot load dll" << "CreateDLL.dll" << std::endl;}system("pause");return 0;
}

注意要将CreateDLL.h和CreateDLL.lib放在项目目录下。

隐式调用:

#include "CreateDLL.h"
#include <iostream>
using namespace std;#pragma  comment(lib,"CreateDLL.lib")int main()
{int a,b;cout << "input 2 num:";cin >> a >> b;cout<<"result is "<<add(a,b);system("pause");return 0;
}

解读:

文件为*.c,__cplusplus没有被定义,extern "C" {}这时没有生效,对于C语言只是extern int add(int, int);而编译c++源文件,__cplusplus被定义,对于C++他看到的是extern "C" {extern int add(int, int);},编译器就会知道add(1, 0)调用的是C连接。 
很多DLL的生成文件(XXX.c)中常出现extern "C" ,windows采用C语言编译创建dll,C程序可以正确调用DLL,而当用户使用C++调用DLL时,extern "C" {}就起作用了。

附录:

1.例1

2.例2



使用extern C改善显式调用dll相关推荐

  1. QT显式调用VC开发的DLL

    首先用visual studio创建dll. 然后通过QLibrary显式调用dll #include "QLibrary"

  2. 阐述Linux动态库的显式调用

    阐述Linux动态库的显式调用 分类: Linux 2011-02-12 10:27 168人阅读 评论(0) 收藏 举报 linux测试nulllibrarypathgcc 十年的发展,Linux系 ...

  3. 基类和派生类的构造函数,隐式调用与显式调用

    1. 顺序        当创建一个派生类的对象时,系统首先自动创建一个基类对象,也就是说,在调用派生类构造函数创建派生类对象之前,系统首先调用基类的构造函数创建基类对象.当派生类对象生命期结束时,首 ...

  4. Java 构造器之构造器的隐式调用和显式调用

    内容参考<疯狂Java程序员的基本修养>李刚 著 一.结论 当调用某个类的构造器来创建Java对象时,系统总会先调用父类的非静态初始化块进行初始化,这个调用是隐式的.接着会调用父类的一个或 ...

  5. C++ dll的隐式与显式调用

     转载自:http://blog.sina.com.cn/s/blog_53004b4901009h3b.html 应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接.在使用D ...

  6. vc++ 显式链接dll

    Visual C++ 显式链接 在显式链接下,应用程序必须进行函数调用以在运行时显式加载 DLL.为显式链接到 DLL,应用程序必须: 调用 LoadLibrary(或相似的函数)以加载 DLL 和获 ...

  7. 没有lib文件的情况下,怎么隐式调用dll

    有时候,总会遇到只有一个dll没有头文件,也没有lib文件的情况下,怎么隐式调用呢? 1.首先要生成lib文件,方法如下: Visual C++ 开发工具提供了两个命令行工具,一个是dumpbin.e ...

  8. 天马行空W:在C++中调用DLL中的函数

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

  9. 在C++中调用DLL中的函数

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

最新文章

  1. 【codeforces 711B】Chris and Magic Square
  2. 股权分配中的三种定时炸弹
  3. Python3数字格式化代码示例
  4. Linux---一台主机部署多版本mysql服务和mysql实例
  5. 【白皮书分享】2021消费者数智化运营白皮书.pdf(附下载链接)
  6. 源码安装natcat
  7. 帮内推 | 免费送50个推荐算法工程师的高薪offer!
  8. TensorFlow on Windows: “Couldn't open CUDA library cudnn64_5.dll”
  9. 【渝粤题库】陕西师范大学152201 公共行政学
  10. 番茄助手Visual Assistx报错The security key for this program currently。。
  11. 删除计算机中的云u盘,win10系统删除360云u盘图标的方法
  12. 全面解析云智慧数据中心统一运管解决方案
  13. 华硕n54u mysql_改华硕[N14U N54U]5G 2G的7620老毛子Padavan固件(私人云储存 ari
  14. uniapp显示服务器请求超时,uniapp发布H5连接服务器超时
  15. cf1111d(退背包)
  16. 树莓派自动饮水机编程示例
  17. AR Kit Core ML 将救百万iOS开发者于水深火热中
  18. cad能整体比例缩小吗_cad怎么把原尺寸图缩小几倍
  19. log4j2 pattern详解
  20. OpenMP - 维基百科,自由的百科全书

热门文章

  1. █年薪20万招聘软件工程师!!!
  2. ios怎样在一个UIImageButton的里面加一些自己定义的箭头
  3. 关于群论证明费马小定理?
  4. 【leetcode 简单】 第一百一十题 分发饼干
  5. 1013 B. And
  6. CodeForces - 976F Minimal k-covering
  7. 信息安全系统设计基础第三周学习总结—20135227黄晓妍
  8. css --- 让不同的浏览器加载不同的CSS
  9. JavaScript --- 渲染数据量大的数组
  10. Linux开发5款实用工具推荐