为什么使用错误的调用约定有时会起作用?

TCS*_*TCS 6 c++ winapi callback calling-convention

我使用"StartServiceCtrlDispatcher"函数在windows中注册一个回调函数(称为ServiceMain),但我声明的回调函数是用错误的调用约定编译的.

问题是,在某些计算机上,当应用程序从回调函数返回时,应用程序崩溃,但在其他计算机上,应用程序没有崩溃.

现在,一旦我发现bug一切正常,但我只是不明白为什么在某些计算机上它能正常工作而不会崩溃?

谢谢!:-)

Che*_*Alf 7

这些都是特定于Windows的,我们在这里不是标准的C++.

检查它的文档StartServiceDispatcher只有一个参数,并声明为WINAPI反过来意味着__stcall调用约定.

对于独立函数,__stdcall是两个主要的调用约定之一.另一个是__cdecl.机器代码级别差异只是谁恢复堆栈指针:__stdcall它是函数本身,而__cdecl它是调用代码.

当函数实际上被__stdcall调用但就像它被调用一样__cdecl,情况是有两次尝试恢复堆栈指针:一个在函数的退出处,一个在调用代码中.函数中的那个将成功.根据调用代码中的尝试的完成方式,它可以彻底解决问题(例如,如果只添加所需的偏移量,将堆栈指针视为相对的),或者它可能没有任何有害影响.但它很可能造成混乱,因为关于从函数返回的堆栈指针值的假设是不正确的.

当函数实际上是__cdecl它本身不会恢复堆栈指针,因为这是调用代码的责任.如果调用代码正在处理它,__stdcall那么调用代码也不会恢复它,因为从调用代码的视图中,函数正在这样做.结果,如果你没有得到早期崩溃(因为破坏的假设),那么重复的调用,比如在一个循环中,将吃掉堆栈空间.

这都是未定义的行为.

Undefined Behavior的一个特性就是它可以做任何事情,包括显然有效......

干杯&hth.,