`
ldb19890624
  • 浏览: 243496 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

函数调用约定与函数名称修饰规则(三)

 
阅读更多

作者:星轨(oRbIt)
E_Mail:inte2000@163.com
转载请注明原作者,否则请勿转载

函数调用约定和名字修饰规则不匹配引起的常见问题

函数调用时如果出现堆栈异常,十有八九是由于函数调用约定不匹配引起的。比如动态链接库a有以下导出函数:

long MakeFun(long lFun);
动态库生成的时候采用的函数调用约定是__stdcall,所以编译生成的a.dll中函数MakeFun的调用约定是_stdcall,也就是函数调用时参数从右向左入栈,函数返回时自己还原堆栈。现在某个程序模块b要引用a中的MakeFun,b和a一样使用C++方式编译,只是b模块的函数调用方式是__cdecl,由于b包含了a提供的头文件中MakeFun函数声明,所以MakeFun在b模块中被其它调用MakeFun的函数认为是__cdecl调用方式,b模块中的这些函数在调用完MakeFun当然要帮着恢复堆栈啦,可是MakeFun已经在结束时自己恢复了堆栈,b模块中的函数这样多此一举就引起了栈指针错误,从而引发堆栈异常。宏观上的现象就是函数调用没有问题(因为参数传递顺序是一样的),MakeFun也完成了自己的功能,只是函数返回后引发错误。解决的方法也很简单,只要保证两个模块的在编译时设置相同的函数调用约定就行了。

在了解了函数调用约定和函数的名修饰规则之后,再来看在C++程序中使用C语言编译的库时经常出现的LNK 2001错误就很简单了。还以上面例子的两个模块为例,这一次两个模块在编译的时候都采用__stdcall调用约定,但是a.dll使用C语言的语法编译的(C语言方式),所以a.dll的载入库a.lib中MakeFun函数的名字修饰就是“_MakeFun@4”。b包含了a提供的头文件中MakeFun函数声明,但是由于b采用的是C++语言编译,所以MakeFun在b模块中被按照C++的名字修饰规则命名为“?MakeFun@@YGJJ@Z”,编译过程相安无事,链接程序时c++的链接器就到a.lib中去找“?MakeFun@@YGJJ@Z”,但是a.lib中只有“_MakeFun@4”,没有“?MakeFun@@YGJJ@Z”,于是链接器就报告:

error LNK2001: unresolved external symbol ?MakeFun@@YGJJ@Z

解决的方法和简单,就是要让b模块知道这个函数是C语言编译的,extern "C"可以做到这一点。一个采用C语言编译的库应该考虑到使用这个库的程序可能是C++程序(使用C++编译器),所以在设计头文件时应该注意这一点。通常应该这样声明头文件:

#ifdef _cplusplus
extern "C" {
#endif

long MakeFun(long lFun);

#ifdef _cplusplus
}
#endif

这样C++的编译器就知道MakeFun的修饰名是“_MakeFun@4”,就不会有链接错误了。

许多人不明白,为什么我使用的编译器都是VC的编译器还会产生“error LNK2001”错误?其实,VC的编译器会根据源文件的扩展名选择编译方式,如果文件的扩展名是“.C”,编译器会采用C的语法编译,如果扩展名是“.cpp”,编译器会使用C++的语法编译程序,所以,最好的方法就是使用extern "C"。

分享到:
评论

相关推荐

    函数调用约定与函数名称修饰规则

    函数调用约定与函数名称修饰规则是编程中至关重要的概念,尤其在使用C/C++时。函数调用约定,也称为调用约定或调用约定协议,规定了函数调用时参数如何入栈、谁负责清理栈以及如何传递返回值。函数名修饰规则则涉及...

    函数调用约定与函数名称修饰规则.pdf

    ### 函数调用约定与函数名称修饰规则 #### 调用约定(Calling Convention) 调用约定是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变以及由谁...

    剖析C++函数调用约定

    C++函数调用约定是编程过程中非常重要的概念,它规定了函数调用时参数传递的顺序、谁负责清理堆栈以及函数名是否需要修饰。在Visual C/C++编译器中,有四种主要的函数调用约定:__cdecl、__stdcall、__fastcall和...

    常用的函数调用约定的比较

    函数调用约定(Calling Convention)在程序设计中扮演着重要的角色,它决定了函数参数如何传递、栈的清理方式以及函数名称如何进行修饰等问题。不同的调用约定对程序性能、可移植性和兼容性等方面都有着直接影响。...

    DLL中调用约定和名称修饰

    ### DLL中调用约定与名称修饰详解 #### 一、调用约定(Calling Convention) 调用约定是在程序设计语言中为了实现函数调用而建立的一种协议。它规定了该语言的函数中的参数传递方式、参数是否可变以及由谁来处理...

    函数调用约定

    在程序设计领域中,函数调用约定(Calling Convention)是定义如何传递参数、清理栈空间以及如何分配寄存器等的一组规则。这些规则对于确保程序正确运行至关重要,尤其是在涉及不同编译器或语言间的交互时。本文将...

    C_C++函数符号生成规则(函数名的修饰);C++ 函数重载.pdf

    在C语言中,函数符号生成规则主要有三种:cdecl调用约定、std call调用约定和fastcall调用约定。 1. cdecl调用约定:函数名前加下划线。 2. std call调用约定:函数名前加下划线,函数名后加”@”符号和真参数字节...

    关于C和C++中函数的调用约定.doc

    在C和C++编程中,函数的调用约定(Calling ...总之,理解并正确使用函数调用约定和函数名修饰规则是避免C和C++程序中常见错误的关键。正确应用这些规则可以保证程序的正确链接和执行,提高代码的兼容性和可维护性。

    函数调用约定.docx

    函数调用约定是编程语言中规定函数调用过程的一个重要机制,主要涉及到参数传递和堆栈清理的责任分配。在C和C++中,不同的调用约定适用于不同的场景,特别是涉及到DLL(动态链接库)和Win API函数时,选择正确的调用...

    DLL创建与函数调用规则

    总的来说,DLL的创建与函数调用规则涉及MFC的使用、DLL类型的选择以及入口函数的编写等多个方面,理解这些规则是开发高效、稳定的Windows应用程序的关键。开发者需要根据具体需求选择合适的DLL类型,并遵循相应的...

    __stdcall调用约定、C调用约定和__fastcall调用约定

    调用约定是编程语言中一个重要的概念,它决定了函数调用时参数如何传递以及栈如何管理。__stdcall、__cdecl和__fastcall各有优势和应用场景,选择合适的调用约定对于优化代码性能和提高程序的可维护性至关重要。了解...

    c/c++中函数调用方式

    在C/C++编程语言中,函数调用方式是程序设计中的关键概念之一,它涉及到如何在函数调用过程中处理参数的传递以及栈空间的管理。根据给定的文件信息,我们可以深入探讨C/C++中几种主要的函数调用方式:__cdecl、__...

    cdecl函数调用,了解printf这样的函数调用,对比stdcall会更清楚.zip

    4. 函数名修饰:`stdcall`函数也会进行名称修饰,但与`cdecl`不同,它的修饰规则是为了适应Windows API,一般不会包含参数类型信息,而是以`@`符号后跟参数总字节数表示。 在C#中,虽然没有直接使用`cdecl`或`...

    函数的几种调用机制

    与stdcall不同的是,函数调用结束后,由调用者负责清理堆栈,这使得C调用约定可以支持参数个数不固定的情况。这也反映了C语言的灵活特性。 3. fastcall调用约定:此调用约定旨在提高参数传递的效率。它将部分参数...

    C语言函数调用规定.pdf

    调用约定定义了参数压栈的方向、谁负责清理栈以及函数名称的修饰规则等。 常见的调用约定有以下几种: 1. **stdcall调用约定**: - 在stdcall约定中,参数从右到左压栈,即最右边的参数最先被压入栈。 - 函数...

    c++调用约定 c++的集中约定分析

    在C++编程中,函数调用约定是一种规范化的机制,用于规定如何传递参数、如何清理栈空间以及如何确定函数名称等。这些约定对程序员来说至关重要,尤其是在需要跨平台或者与非C++代码进行交互的情况下。本文将深入解析...

    C语言函数调用规定[文].pdf

    理解函数调用约定对于编写跨平台或与特定编译器交互的代码至关重要。不同的编译器可能有不同的默认调用约定,或者提供自定义约定的选项。例如,fastcall调用约定通常用于优化性能,通过寄存器传递部分参数,减少堆栈...

    Windows调用约定.pdf

    Windows调用约定是指Windows平台下函数调用时的规则和约定,它是编译器在生成函数调用代码时遵循的一套机制,以确保调用方与被调用方之间能够正确地传递参数和处理函数返回值。在C++和C语言中,这些调用约定对程序的...

Global site tag (gtag.js) - Google Analytics