我与 Run-Time Check #0 的第一次亲密接触

 某一天写程序,调试时突然出现如下的错误提示:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

我很少遇到类似的C++运行时检查错误,至于什么堆栈指针丢失就更不用说啦,因为我写的代码全是按照C++默认的函数调用约定,应该不会出现函数声明和函数指针定义的调用约定不一致的情况。

问题总是要解决的。跟踪代码,发现每次调用IComm对象的函数时就出现该错误。查看该对象的状态,发现IComm的子类状态乱七八槽,不是预期的状态。

这里先说一下类的结构。
IComm: 通信器接口,抽象类
ISerial: 串口通信接口,抽象类
CSerial: 串口通信对象,同时实现IComm和ISerial接口(继承自IComm和ISerial)

我是这样初始化的:
ISerial * pSerial = new CSerial();  // 语句1
pSerial->SetPort(4);
pSerial->SetBaud(19200);
IComm * pComm = (IComm *) pSerial;  // 语句2
// 保存pSerial和pComm

跟踪发现,执行语句2后,pSerial的CSerial子类状态是Port=4, Baud=19200;而pComm的CSerial子类状态却不是!

把语句2改为:
IComm * pComm = (CSerial *) pSerial;
后,状态正确了,Run-Time Check Failure #0 也消失了。

分析:C++在父类子类相互类型转换的时候,如果不正确地指定转换路径,那么,对象的子类状态和函数入口地址等内存将错位,所以运行时类型检查时,出现堆指针丢失的错误,而不是什么函数调用约定不一致。

出现这种错误是由于我对C++的类型转换不熟悉的结果。我一直使用C的类型转换样式,我想当然以为C++会帮我们把父子类类型转换路径完全做好。以后要复习一下C++类型转换了。

你可能感兴趣的:(c,function)