`
bcyy
  • 浏览: 1836740 次
文章分类
社区版块
存档分类
最新评论

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 );
}



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics