分类:
2012-01-16 21:12:57
原文地址:嵌入式软件中基于栈的错误追踪机制设计 作者:define_shore_me
1 建立全局错误代码表
对于嵌入式软件来说,尽量节省内存资源、降低程序代码量是十分重要的。因此,将程序中所有错误、异常情况都进行了统一编码,提高了错误处理代码的规范化与可读性。设计8位整数编码格式如下:
每个错误代码在程序中仅需要1个字节进行存储。对于程序中每个可能异常的地方(如COM1没打开),都设定1个唯一编号,当出现错误或异常时根据该编号可以直接定位到源程序对应文件和程序段,并确定错误类型。
采用错误代码的形式存储错误信息,不仅可以精确描述错误的类型、位置等信息,还可以最大限度地节省宝贵的可执行内存资源,降低程序对内存的需求。
2 建立全局异常堆栈
在一个复杂的嵌入式实时系统中,程序处理流程复杂,不同资源之间往往在操作上存在着交叉。当出现程序错误或异常时,不能简单地退出程序,而是应当尽量将错误处理掉,实在无法处理的错误应进行记录,但整个程序的运行不应当中断。对此,使用1个错误堆栈来保存错误信息。该栈用下面数组定义:
ERROR_STACK为全局错误栈类型定义,MainErrStack为全局栈实例,其元素个数由ERR_STACK_SIZE确定。ErrorParm为字符数组,当错误发生时可以依次保存函数的人口参数以及异常发生之前局部变量的值等。实际数组长度ERR_ENV_LEN可以根据情况调整,一般情况下开发阶段可以设置大一些,保证存放更多的错误信息用于调试;进入实际运行阶段可以适当缩小该错误环境栈长度,减少内存空间的占用。
为了确保错误处理机制本身不会给程序引入新的异常,因此将堆栈的操作完全封装为Push和Pop两个函数,并引入当前堆栈指针stackCu-rrentPos(初始为一1表示堆栈为空,有效取值范围为一1~ERR_STlACK_SIZE一1,该指针始终指向栈顶元素)。算法说明如下:
3 建立统一的错误描述字典表
为了进一步提高代码规范化程度并降低内存需求,可以将每种类型的错误定义一个错误描述保存在单独的文件或缓冲区中。当发生错误时,系统根据错误代码取出该错误的详细描述并显示给用户。以上操作可以封装为ShowErrorMessage函数,定义为Char*ShowErrorMessage(int errorId)。在错误发生位置并不直接描述错误信息的方法,不仅可以降低可执行内存需求,而且避免了由于不同开发者对错误文字描述的差异而导致对用户的提示信息不统一。例如错误提示“数组越下界!代码:53017010”,530即表示数组越下界异常,17表示编号为“17”的C源程序文件,010表示文件中第10个错误位置。部分错误代码描述示例如表1所列。
4 应用说明
下面以1个简单的例子来说明本文方法的运行。假设程序需要提供1个通过GPRS发送数据的函数GprsSendData(char*ip,char*buf,int size),实现将buf缓冲区指定长度为size的字符串通过TCP方式发送到给定IP地址。示例代码如下:
由上面可以看出,可能出现错误的位置都加入了错误压栈操作,当GprsSendData函数的返回值为假时,上级调用函数会继续将其异常时的运行状态(局部变量、参数等)继续压栈,以此类推直到需要处理该异常的最顶级。开发人员后期调试时可以将栈顶元素依次出栈,构成一条完整的函数调用链,比较容易找出上述产生ip为空串的根本原因。
在软件开发阶段及运行的初期阶段,适当加大错误堆栈容量,可以储存更多信息辅助调试。随着设备软件可靠性、稳定性的增加,在正式投入运行后可以将异常栈设定为较小的容量,以降低存储需求。
可以设想,若整个嵌入式软件在开发中严格按照本文思路处理异常,应当可以很方便地进行异常的查找与处理。当嵌入式设备投入运行后,定期对该设备的错误栈进行分析,对于栈中存储的错误信息进行及时处理,可以迅速有效地增加设备软件的运行可靠性。一个经过严格测试的设备在绝大多数情况下错误栈应为空。
结语
本文对于基于C语言的嵌入式软件开发中的错误追踪机制进行了详细描述。该机制可以有效地降低软件异常发生的概率,提升软件的可靠性,减少开发成本。同时,该机制亦可以用于正常开发阶段的辅助调试中,在关键程序段将环境信息压栈实现后期分析,也为改进嵌入式软件的调试手段提供了新的辅助思路。文中所述机制已经在作者主持的电力GPRS集抄终端的软件设计中得到了实际应用,取得了良好的效果。