C++愤恨者札记3——函数调用约定

C++愤恨者札记3——函数调用约定

函数调用约定指的是,参数压栈顺序及弹栈位置的约定。这个约定在函数声明时指定,如:

void__stdcallFn(intarg1,intarg2);

其中__stdcall就是调用约定,表示参数从右至左入栈,而函数自己负责参数弹栈工作。

还有一种常用约定为__cdecl,表示参数从右至左入栈,而函数调用者负责参数弹栈工作。

如果没有指定调用约定,编译器会使用默认约定。VS中默认约定可以在工程属性中设置:


VC++中,一般函数使用__cdecl约定,但类成员函数,包括构造函数,使用__stdcall约定(我不知道为什么),从它们的反汇编代码中可以看出。

源码:

class Node
{
public:
	Node(){}
	void Fn( int a, int b ){}
};

void Fn(int a, int b)
{
}

void main()
{
	Node n;
	n.Fn(1, 2);

	Fn( 1, 2);
}
main与Fn反汇编代码如下:

-------------------------------------------------------------------------------------------------------------------

函数调用约定在汇编中,区别是巨大的,而在高级语言里却很少进入视野。下面给出一个因约定不一致导致程序崩溃的例子。程序要在 debug 版本下编译,或 release 版下把 /Od 打上,禁止优化,否则可能看不到程序崩溃。

typedef void (__cdecl *CDeclType)(void*);

void __stdcall Fn(void* p)
{
}

void MyCallBack( CDeclType pFn )
{
	pFn(0);	/*pFn的参数将会被两次弹栈,
			破坏栈平衡MyCallBack将找不到返回地址*/
}

void main()
{
	MyCallBack( (CDeclType)Fn );
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值