_imp和__imp有什么区别?

时间:2012-06-28 00:58:05

标签: visual-c++ dll linker mingw

当我在Qt Creator中使用MinGW尝试链接到MSVC编译的库时,我遇到了一个有趣的错误。链接器抱怨缺少符号_imp_FunctionName。当我意识到它是由于缺少extern“C”并修复它时,我还使用/ FAcs运行MSVC编译器以查看符号是什么。事实证明,它是__imp_FunctionName(这也是我在MSDN和很多大师博客网站上阅读的方式)。

我对MinGW链接器如何抱怨以_imp开头的符号感到非常困惑,但是虽然它以__imp开头,却能很好地找到它。深度编译魔术师可以对此有所了解吗?我使用的是Visual Studio 2010。

1 个答案:

答案 0 :(得分:21)

这是工作中相当直接的标识符装饰。 imp_前缀由编译器自动生成,它导出一个函数指针,允许优化与DLL导出的绑定。根据语言规则,imp_以前导下划线为前缀,因为它位于全局命名空间中并且由实现生成,因此不会出现在源代码中。所以你得到_imp_

接下来发生的事情是编译器修饰标识符以允许链接器捕获声明不匹配。非常重要,因为编译器不能诊断模块之间的声明不匹配,并且在运行时自己诊断它们非常很痛苦。

首先是C ++装饰,一个支持函数重载的非常复杂的方案。它产生了非常奇怪的名字,通常包括很多?和带有参数和返回类型的额外字符的@字符,以便重载是明确的。然后是C标识符的装饰,它们基于调用约定。 cdecl函数有一个前导下划线,stdcall函数有一个前导下划线和一个尾随@n,它允许在它们使堆栈不平衡之前诊断参数声明不匹配。在64位代码中没有C装饰,(祝福)只有一个调用约定。

因此您忘记指定C链接时出现链接器错误,要求链接器将装饰较重的C ++名称与温和装饰的C名称匹配。然后,您使用extern "C"修复了它,现在您为cdecl添加了单个下划线,将_imp_转换为__imp_