您的位置:首页 > 其它

名字改编(name mangling)、调用约定与对策

2010-09-04 14:09 239 查看
转自:http://blog.csdn.net/wild_fox86116/archive/2007/10/21/1836149.aspx

以vc为例,
1。c和c++之间:
void foo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int
之类的名字用来支持函数重载和类型安全连接.由于编译后的名字不同,C++程序不能
直接调用C函数.C++提供了一个C连接交换指定符号extern"C"来解决这个问题.
2。不同编译器之间:
即使是按照c链接,但是不同的调用约定,比如__stdcall 和 __cdecl调用也会产生不同的名字改编。
---------------------------------------------------------
关于调用约定
---------------------------------------------------------
调用约定 堆栈清除 参数传递
__cdecl 调用者 从右到左,通过堆栈传递
__stdcall 函数体 从右到左,通过堆栈传递
__fastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈
thiscall 函数体 this指针默认通过ECX传递,其它参数从右到左入栈
note:
(1)__cdecl是C/C++的默认调用约定;
VC的调用约定中并没有thiscall这个关键字,它是类成员函数默认调用约定;
C/C++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改;
默认调用约定一般能够通过编译器设置进行更改,如果你的代码依赖于调用约定,请明确指出需要使用的调用约定;
(2)常见的函数调用约定中,只有cdecl约定需要调用者来清除堆栈;C/C++中的函数支持参数数目不定的参数列表,比如printf函数;由于函数体不知道调用者在堆栈中压入了多少参数,所以函数体不能方便的知道应该怎样清除堆栈,那么最好的办法就是把清除堆栈的责任交给调用者;这应该就是cdecl调用约定存在的原因吧;
---------------------------------------------------------
C编译在进行编译的时候也会进行名字的改编,当函数使用_stdcall(WINAPI)调用规则时,MS编译器就会改编函数的名称。
比如:__declspec(DLLexport) LONG __stdcall Proc(int a ,int b);
编译器会改编为__Proc@8
因此 当非C++或非C编译器调用该DLL中的函数Proc时,就会出现找不到函数的情况。
这样我们就可以定义DEF文件来解决,并且在DEF文件加上下面的EXPORTS:
EXPORTS
Proc
Def模块执行原理:当连接程序分析这个DEF文件时,它发现Proc和__Proc@8都被输出,由于这两个函数是相互匹配的,因此连接程序使用Proc来输出该函数,根本不使用__Proc@8来输出函数名
(3)下面是
调用习惯  VC++命名 C++Builder命名
---------------------------------------
__stdcall _MyFunction@4 MyFunction
__cdecl MyFunction _MyFunction
可以从网上搜索“在C++Builder里创建可以被Visual C++使用的DLL”以及“Using Visual C++ DLLs in a C++Builder Project”这两篇文章,看看不同编译器生成的dll之间是如何互相调用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: