一般地,我们在新建一个win32的动态链接库(DLL)时,会采取如下的方式的来编写导出接口文件(.h)。

#pragma once#ifndef API_EXPORT
#define DECL_API extern "C" __declspec(dllimport)
#else
#define DECL_API extern "C" __declspec(dllexport)
#endifDECL_API int Add(int a, int b);

如上代码,主要使用了一组预编译宏。这样设计的好处是,可以复用这个头文件。复用的方法是:

1)在客户端,正常包含该头文件即可。不要定义“API_EXPORT”,这个宏。这样客户端编译时将把所有接口看作导入函数。

2)在DLL端,接口函数的实现文件中(.cpp),需要定义宏“API_EXPORT”。这样,DLL编译时将把接口函数当作导出函数。

问题:

在接口函数的实现文件中,需要非常小心宏“API_EXPORT”的定义行与接口头文件包含代码行的位置关系。否则容易导致编译错误,特别是用VS的预编译头文件后。

举例:

用VS2015(其他版本也可以)新建一个名为“Export”的win32 DLL工程(其他默认)。它将生成几个文件,其中关键的文件有:

1)Export.cpp    :  在此实现接口函数。

2)stdafx.h        :预编译头文件

3)dllmain.cpp :    DLL的入口函数。

第一步:

添加一个名为“Export.h”的头文件,代码如上面的代码段。

第二步:

将该头文件包含到“Export.cpp”,并定义“API_EXPORT”宏,然后实现接口函数。如下:

// Export.cpp : 定义 DLL 应用程序的导出函数。
//#include "stdafx.h"#include "Export.h"
#define API_EXPORTDECL_API int Add(int a, int b)
{return a + b;
}

此时,编译报错:“error C2491: “Add”: 不允许 dllimport 函数 的定义”

分析:

很明显,“API_EXPORT”宏的定义应该在包含头文件之前,否则,这个宏没有起作用。

第三步:

调整“API_EXPORT”宏的定义的位置如下:

// Export.cpp : 定义 DLL 应用程序的导出函数。
//
#define API_EXPORT
#include "stdafx.h"#include "Export.h"DECL_API int Add(int a, int b)
{return a + b;
}

编译还是报错,错误信息同上一条。是不是很纳闷???

分析:

再仔细看编译输出,发现在这个Error信息之前,还有一条warning信息和两条note信息,如下:

warning C4603: “API_EXPORT”: 未定义宏或在预编译头使用后定义发生改变
note: 将宏添加到预编译头中,而不是在此处定义
note: 使用预编译头

原来,宏的定义不能放在VS自动生成的这个“stdafx.h”之前,否则也无效。

第四步:

再次调整“API_EXPORT”宏的定义的位置如下:

// Export.cpp : 定义 DLL 应用程序的导出函数。
//#include "stdafx.h"
#define API_EXPORT
#include "Export.h"DECL_API int Add(int a, int b)
{return a + b;
}

编译通过,能够正常导出。

总结:

1)不要忽视warning和note信息。

2)要留意“stdafx.h”。

VS中DLL的导出宏的定义和头文件的位置导致的两类编译错误总结相关推荐

  1. c++中类的定义与头文件的关系

    class Stack: 此句只是作为Stack class的前置申明,只是将calss名次告诉编译器,并未提供此class的任何其他信息.前置申明使得我们可以进行类指针的定义,或以此class作为数 ...

  2. c++dll导入导出宏定义,出现“无法定义dllimport 实体”和“不允许dllimport 静态数据成员的定义”的问题

    问题如下: 建立dll项目后,在Api_Head.hpp头文件中,定义宏: #ifndef API_HEAD_HPP #define API_HEAD_HPP #ifdef API_DLL_COMPI ...

  3. 将类的定义放在头文件中,把成员函数的实现代码放在一个cpp文件中

    将类的定义放在头文件中,把成员函数的实现代码放在一个cpp文件中 写这种.h和.cpp文件分开的大程序,虽然对很多人来说很简单,对自己来说算是第一次吧,好好学C++,加油~ 题目:定义Point类,由 ...

  4. 使用jspdf插件将网页中的内容导出为高保真的pdf文件

    文章目录 使用jspdf插件将网页中的内容导出为高保真的pdf文件 1. 将网页中的内容导出为pdf文件的四种方式比较 2. 第一种方式:html2canvas + jspdf 导出网页内容 2.1 ...

  5. 习题 8.4 在本章第8.3.3节中分别给出了包含类定义的头文件student.h,包含成员函数定义的源文件student.cpp以及包含主函数的源文件main.cpp。请完善该程序,在类中增加。。。

    C++程序设计(第三版) 谭浩强 习题8.4 个人设计 习题 8.4 在本章第8.3.3节中分别给出了包含类定义的头文件student.h,包含成员函数定义的源文件student.cpp以及包含主函数 ...

  6. 习题 8.5 将本章的例8.4改写为一个多文件的程序:1.将类定义放在头文件arraymax.h中;2.将成员函数定义放在源文件arraymax.cpp中;3.主函数放在源文件file1.cpp中。

    C++程序设计(第三版) 谭浩强 习题8.5 个人设计 习题 8.5 将本章的例8.4改写为一个多文件的程序: 1.将类定义放在头文件arraymax.h中: 2.将成员函数定义放在源文件arraym ...

  7. C++声明、定义、类的定义、头文件作用、头文件重复引用

    转载至:点击打开链接 C++声明.定义.类的定义.头文件作用.头文件重复引用,不具名空间 转自:http://www.cnblogs.com/rocketfan/archive/2009/10/02/ ...

  8. C++ : 编译单元、声明和定义、头文件作用、防止头文件在同一个编译单元重复引用、static和不具名空间...

    转 自:http://www.cnblogs.com/rocketfan/archive/2009/10/02/1577361.html 1. 编译单元:一个.cc或.cpp文件作为一个编译单元,生成 ...

  9. CCS中给工程加入C66x CSL库和头文件

    CCS中给工程加入C66x CSL库和头文件 下载CSL头文件和库. 下载后解压缩进行安装,我安装的位置为:C:\ti\C6xCSL,装好后"/include/"文件夹下面是CSL ...

最新文章

  1. 10-20国际电极标准系统
  2. 5G 标准 — R15
  3. 一维数组和二位数组作为函数参数进行传递的方式
  4. Java多线程(二):Callable和FutureTask结合使用获取返回值
  5. 当退出python时是否释放全部内存_Python面试题:高级特性考察
  6. 二维数组求最大子矩阵的和
  7. vba 当前文件名_VBA实践+批量合并pdf
  8. mysql 分区信息查看
  9. 电脑安装python后开不了机_ubuntu 安装python3.6后,terminal终端打不开问题
  10. Linux笔记-rpm与yum的基本概念
  11. android+场景切换,Android共享元素场景切换动画的实现
  12. java循环输出_Java实现excel导出(内容循环多个)
  13. Java 1.7 ThreadPoolExecutor源码解析
  14. 使用StarUML生成live555类图
  15. C++11新特性 右值引用与移动语义
  16. C语言实现行列式计算
  17. 2.8 转置矩阵及对称矩阵
  18. 常用公差配合表图_常用的机械测量工具竟然这么多?你知道几个?
  19. 汤普森算法_什么是汤普森采样(Thompson sampling)?
  20. ARGB颜色与int相互转换

热门文章

  1. 基于SpringBoot+Vue的美食分享平台
  2. 行业分享 | 苏宁聚力:企业内部的一体化数智工作平台
  3. [附源码]计算机毕业设计JAVA企业人力资源管理系统
  4. 金升阳 | 更轻更小的R3系列金属导轨电源 ——LI75/120-23BxxR3
  5. 事件循环-宏任务-微任务
  6. 国家公务员考试万余岗位发布 国税系统招人最多-国家公务员-公务员考试-岗位
  7. 对BRD、MRD、PRD、FSD四类产品文档的理解
  8. 论文笔记:DS-SLAM
  9. Javaweb-初识(Tomcat服务部署、创建Javaweb项目、Servlet Post请求案例)
  10. uniapp webview 直接调用原生摄像头拍照 拍视频 img video,通过ajax获取blob(file为特殊的blob)对象并上传到后端服务器