zlib报“LNK2001:无法解析的外部符号”错误
这个错误一般是由使用导出dll时未加载对应的lib文件导致的,但是工程在正确配置了lib文件的情况下仍然报这个错误,经查,是由于dll导入工程和dll导出工程的函数调用约定不一致导致的。
一、函数调用约定
首先,我们由函数的调用约定说起,microsoft的vc默认的是__cdecl方式,而windows API则是__stdcall,如果用vc开发dll给其他语言用,则应该指定__stdcall方式。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作,如果是__cdecl方式的函数,则函数本身(如果不用汇编写)则不需要关心保存参数的堆栈的清除,但是如果是__stdcall的规则,一定要在函数退出(ret)前恢复堆栈。
windows有如下五种调用约定:
1.__cdecl
所谓的C调用规则。按从右至左的顺序压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的。返回值在EAX中因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的时候对这种调用规则的函数生成修饰名的饿时候,仅在输出函数名前加上一个下划线前缀,格式为_functionname。
2.__stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,切记:函数自己在退出时清空堆栈,返回值在EAX中。 __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_functionname@number。如函数int func(int a, double b)的修饰名是_func@12。
3.__fastcall
__fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@functionname@number。这个和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第一个参数进ECX,第2个进EDX,其他参数是从右向左的入stack。返回仍然通过EAX。
4.__pascal
这种规则从左向右传递参数,通过EAX返回,堆栈由被调用者清除。
5.__thiscall
仅仅应用于"C++"成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。
二、解决方法
之所以会报LNK2001,是因为编译zlib(dll)的工程默认有预处理器定义ZLIB_WINAPI,ZEXPORT在zconf.h中的定义为WINAPI:
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
# define ZEXPORTVA FAR CDECL
# endif
# endif
#define WINAPI __stdcall
所以,zlib(dll)的导出函数调用约定为__stdcall,和zlib(dll)的导入函数调用约定__cdecl不一致。
针对zlib编译dll文件编译出错,有以下两种解决办法:
1. 在zlivc工程中去掉预处理器定义ZLIB_WINAPI(预处理定义:vs工程属性->C/C++->预处理器)
去掉该定义后,宏定义ZEXPORT在zconf.h文件中实际定义如下:
#ifndef ZEXPORT
# define ZEXPORT
#endif
所以导出函数unzGoToNextFile
extern int ZEXPORT unzGoToNextFile (unzFile file)
等价于
extern int unzGoToNextFile (unzFile file)
也等价于(vs默认是__cdecl函数调用约定)
extern int __cdecl unzGoToNextFile (unzFile file)
所以在新的工程中导入zlib相关的库文件和dll文件后,编译dll的工程和引入dll的工程的函数调用约定均为__cdecl方式,导出函数能够正确解析了,编译自然就通过了。由上宏定义注释可知,标准编译ZLIB1.DLL是没有ZLIB_WINAPI预处理定义的,函数调用约定也是__cdecl,所以这里推荐该解决方案。
2. 在引入zlib工程中添加预处理器定义ZLIB_WINAPI
在引入dll工程中添加ZLIB_WINAPI定义后,宏定义ZEXPORT在zconf.h文件中实际定义如下:
# define ZEXPORT WINAPI
#define WINAPI __stdcall
与导出zlib的dll工程均为__stdcall函数调用约定,编译也能顺利通过。
zlib报“LNK2001:无法解析的外部符号”错误的更多相关文章
- 引用rtmp编译报错:rtmp.obj : error LNK2001: 无法解析的外部符号 __imp__timeGetTime@0
如题vs下引用librtmp的时候报错:rtmp.obj : error LNK2001: 无法解析的外部符号 __imp__timeGetTime@0 在link 里加入 winmm.lib 就可以 ...
- vs2015编译ffmpeg 出现错误rtmp.lib(rtmp.obj) : error LNK2001: 无法解析的外部符号 ___iob_func
vs2015编译ffmpeg(版本3.0.2)引用外部库文件librtmp出现以下错误: rtmp.lib(rtmp.obj) : error LNK2001: 无法解析的外部符号 __imp__st ...
- vs2010+qt4编译出现error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject等错误
1.当vs2010编译qt时会出现以下错误: 1>------ 已启动全部重新生成: 项目: MyDialog, 配置: Debug Win32 ------ 1>生 ...
- c++中调用python脚本提示 error LNK2001: 无法解析的外部符号 __imp_Py_Initialize等错误的解决方法
最近项目中需要实现一个服务器宕机后短信提醒的功能,个人觉得在使用Python 写http请求这块很方便,发短信这块就使用了python,但是c++程序中调用这个脚本时,编译不通过,提示如下错误: er ...
- colmap编译过程中出现,无法解析的外部符号错误 “__cdecl google::base::CheckOpMessageBuilder::ForVar1(void)”
错误提示: >colmap.lib(matching.obj) : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: cl ...
- error LNK2001: 无法解析的外部符号
1.错误描述 error LNK2001: 无法解析的外部符号 "__declspec(dllimport) void __cdecl PadSystem::Private::printQS ...
- C++工程编译之“error LNK2001: 无法解析的外部符号”
今天一整天都在折腾“error LNK2001: 无法解析的外部符号”,就在头疼不已的时候,总算是找到问题原因了:各个动态链接库的编译方式必须统一才行,要不然很容易对库函数的引用产生冲突.简单来说就是 ...
- error LNK2001: 无法解析的外部符号 解决方法
错误提示:LNK2001 无法解析的外部符号 "public: class el::base::Writer & __cdecl el::base::Writer::construc ...
- 【转】strmbasd.lib(dllentry.obj) : error LNK2001: 无法解析的外部符号"int g_cTemplates"
加入了DirectShow的基类链接库后,如果此时编译就会出现以下编译错误: strmbasd.lib(wxutil.obj) : error LNK2019: 无法解析的外部符号 __imp__ti ...
随机推荐
- 游戏UI框架设计(五): 配置管理与应用
游戏UI框架设计(五) --配置管理与应用 在开发企业级游戏/VR/AR产品时候,我们总是希望可以总结出一些通用的技术体系,框架结构等,为简化我们的开发起到"四两拨千金"的作用.所 ...
- docker - win7下构建swarm nodes实现跨host的容器之间的通信
前言 之前在Linux环境下尝试了swarm,通过将不同host以swarm nodes 的方式连接到一起(构建Overlay 子网),从而实现跨host的container通信. 今天我们就来说说如 ...
- Python成长之路 — 字典
一.字典的定义与创建 字典是Python中唯一内建的映射类型.你可以将其想象成书本的目录,章节名称代表"key",页码则代表"value".书本的目录本质上是也 ...
- bootstrapValidator 使用(包含入门demo,常用方法,以及常用的规则)
一 什么是bootstrapValidator? -- 一个基于 jquery,boostrap 的表单验证框架....简单实用上手快,页面美观还过得去,不废话了,直接撸. 二 boots ...
- profiler内存优化:警惕回调函数
最近做profiler内存优化,踩了一个深坑,觉得有必要做一下笔记. 过程是这样的,游戏启动后,会启动更新模块,加载更新界面,更新检测完成后会切换场景进入登陆界面.切换场景会自动释放上一个场景的资源. ...
- 影响国内WinCE7发展的最大障碍是没有D版下载
WinCE红火的时代已经过去,做嵌入式系统时考虑WinCE的越来越少,网络上相关文章也是越来越少. 但真正用过WinCE的应该有体会,它集成了文件系统,tcp/ip,GUI系统,usb驱动,就这些,你 ...
- iOS,Android,Jave后台AES加密解密
AES256 在iOS和Android上的相关代码: http://www.tuicool.com/articles/RVFbmmU 里面可以下载相关的代码. 我们遇到的问题是: 把Android的代 ...
- Deep Q-Network 学习笔记(一)—— Q-Learning 学习与实现过程中碰到的一些坑
这方面的资料比较零散,学起来各种碰壁,碰到各种问题,这里就做下学习记录. 参考资料: https://morvanzhou.github.io/ 非常感谢莫烦老师的教程 http://mnemstud ...
- 有关Dom的一些操作
学习前端的都会了解到一些Dom操作,让我们来看看Dom操作有哪些吧! DOM(即 Document Object Mode) 是 W3C(万维网联盟)的标准. DOM 定义了访问 HTML 和 XML ...
- 关于cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题(不需要修改任何代码,只需要一个配置)
前言:今天在网上无意间看到cas单点登录排除请求的问题,发现很多人在讨论如何通过改写AuthenticationFilter类来实现忽略/排除请求URL的功能:突发奇想搜了一下,还真蛮多人都是这么干的 ...