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

以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之间是如何互相调用的。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值