C++:调用协定


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

调用协定这个东西涉及到C语言函数实现的原理,大家都知道,调用函数时,保存当前执行环境,跳转到目标函数指令地址执行函数代码,执行完成后恢复调用前的执行环境。但实现的方式这么多,甚至可能不同的语言提供的接口有不同的方式,如何实现与目标函数相同的方式来调用呢?调用协定因此诞生。
可能有人觉得,这东西我从没听说过,但我写的C艹代码一样没问题,有必要研究吗?说实话这东西还是有必要的,主要在不同框架、语言间使用。比如BCB主要用__fastcall实现函数调用,C语言自身默认使用__cdecl实现函数调用,Windows平台又以__stdcall作为主要函数调用方式,而.NET Framework托管平台又以__clrcall实现函数调用,它们之间如何互相调用就是个问题。
Win32平台上可用函数调用协定有以下几种,后面的为别名:
__cdecl : _cdecl 、 cdecl 、 CDECL 、 WINAPIV
__pascal : pascal 、 PASCAL
__stdcall : WINAPI 、 APIENTRY 、 CALLBACK 、 APIPRIVATE
__fastcall
__clrcall
可能因为操作系统版本不同,导致函数定义有些许差异,在Win8.1上,__pascal已经被定义成了__stdcall,但并不妨碍我们对调用协定的学习。上面的关键字看不懂?没关系,我们一一来验证它们的作用。

1、__cdecl调用协定

首先__cdecl,C语言默认调用协定。首先我们先定义一个这样的函数,然后对其进行调用。

1
2
3
4
5
int __cdecl func_cdecl (int a, int b, int c) {
    return a + b + c;
}
//...
func_cdecl (1, 2, 3);

调用协定的定义方式为,将名称写在返回类型与函数名之间。写完之后,通过对齐进行Disassembly,显示如下结果:
20160910230845-cdecl
20160910230845-cdecl-call
继续阅读C++:调用协定