VS中DLL的导出宏的定义和头文件的位置导致的两类编译错误总结
2016-12-29 14:59
369 查看
一般地,我们在新建一个win32的动态链接库(DLL)时,会采取如下的方式的来编写导出接口文件(.h)。
#pragma once
#ifndef API_EXPORT
#define DECL_API extern "C" __declspec(dllimport)
#else
#define DECL_API extern "C" __declspec(dllexport)
#endif
DECL_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_EXPORT
DECL_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”宏的定义的位置如下:
编译通过,能够正常导出。
总结:
1)不要忽视warning和note信息。
2)要留意“stdafx.h”。
#pragma once
#ifndef API_EXPORT
#define DECL_API extern "C" __declspec(dllimport)
#else
#define DECL_API extern "C" __declspec(dllexport)
#endif
DECL_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_EXPORT
DECL_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”。
相关文章推荐
- 将DLL中的导出函数表导出到一定义(.DEF)文件
- vs c++ Rebuilt 编译时不能生成 .dll文件
- Mongo导出数据文件导致错误 Got signal: 6 (Aborted)解决方法
- 虚拟机linux共享文件的编译错误总结
- VS编译出现将元数据写入文件“x:/x/obj/Debug/xx.exe”时发生错误 --“存储空间不足,无法完成此操作。 ”
- 错误与修复:ASP.NET无法检测IE10,导致_doPostBack未定义JavaScript错误,恒处于FF5卷动条位置
- vs2013编译google protobuf生成的消息文件错误。
- vs2008中定义dll,通过def文件导出接口
- VS开发环境常见编译错误——LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- 使用 DEF (模块定义) 文件从 DLL 导出函数和类
- Makefile 多文件编译错误总结
- 关于包含头文件而编译时却一个未定义错误的原因(未使用命名名字空间)
- win7 VS2012 编译可在XP下调用的dll文件
- afxwin.h这个头文件可能会导致编译错误
- hibernate配置文件中重复定义导致的错误:should be mapped with insert="false" update="false"
- 建立工程后刚开始编译出现了“error PRJ0003 : 生成 cmd.exe 时出错”这样的错误,虽然在debug中生成了.exe文件,但是无法执行,提示找不到mfc90ud.dll。
- 抽取VS文件组成类GCC的编译器,并编译C程序为dll动态链接库
- 结构体的定义位置不正确导致的错误
- vs2010打包程序制作的快捷方式指向错误的位置(指向安装包文件) 导致每次启动都要windows正在配置
- VS2012 编译程序时报无法加载PDB文件错误解决方案