用编译时断言在早期发现错误

用编译时断言在早期发现错误

ID:21109878

大小:57.50 KB

页数:4页

时间:2018-10-19

用编译时断言在早期发现错误_第1页
用编译时断言在早期发现错误_第2页
用编译时断言在早期发现错误_第3页
用编译时断言在早期发现错误_第4页
资源描述:

《用编译时断言在早期发现错误》由会员上传分享,免费在线阅读,更多相关内容在学术论文-天天文库

1、用编译时断言在早期发现错误

2、第1...用编译时断言在早期发现错误一段时间以来,笔者一直在讨论如何在C和C++中使用结构来定义存储器映射器件寄存器的布局,并曾讨论了可以用来为相应寄存器给每个结构成员以合适的尺寸和排列。然而,不同的平台对数据的排列和填充不一样。因此,一个特定的结构定义对一个平台能正确布局结构成员,但对另外一个不同的平台进行编译时,可能会产生错误的布局。一种不正确的布局结构在编译时常常没有告警出现,但是最终的程序在运行时不能按所期望的那样工作。你可以改进代码而不用费时费力地调试,这样编

3、译器能发现布局错误。其中的技巧就是利用断言(assertion),断言能在结构成员出现尺寸或者排列错误时生成明显的编译时(pile-time)错误。C和C++提供了实现断言的不同方法。笔者偏爱于那些能提供标准C断言宏编译时对等量的方法。我们从简要了解一下这个宏开始。运行时(Run-time)断言断言宏在标准的C头文件和标准的C++头文件中定义。形式为:assert(condition);的调用扩展到测试条件的代码。如果条件为真(产生一个非零值),将什么也不会发生。即在宏调用之后,程序继续执行下一个

4、语句。另一方面,如果条件为假(等于零),程序写一个诊断消息到stderr(标准错误流),并通过调用标准中断函数终止程序的执行。断言宏能帮助在程序中发现逻辑错误。例如,假设调用get_token(f,t,n)扫描来自FILE*f的输入,并将扫描的输入拷贝到字符数组中,以*t开头,长度为n,可以在get_token中调用断言来发现错误的自变量值,否则将导致产生不确定的行为,如下面的函数:boolget_token(FILE*f,char*t,size_tn){...assert(f!=NULL);as

5、sert(t!=NULL);assert(n>=2);...}如果程序不经意地用一个空指针作为第一个自变量来调用get_token函数,第一个断言将向stderr写入一个消息,并中断执行。对于大多数编译器来说,消息看起来类似于:Assertionfailed:f!=NULL,fileget_token.c,line18将断言写入到代码中能帮助进行归档,并提高开发代码的成功率。然而,因为是写到stderr,在缺乏对标准CI/O系统支持的嵌入式环境中,标准的断言宏毫无用处。然而,写你自己的断言宏

6、版、在别的地方显示消息并不那么困难。尽管断言宏可以是一种有用的调试辅助手段,但并不适合于处理在已付运的终端用户产品中的运行时错误。已付运的产品应该产生对于一般终端用户来说很有意义的诊断消息。它还应该比通过调用中断函数更可靠地恢复或关断程序的执行。因此,提供了一种在源代码很少或不改变的情况下使所有断言无效的简单方法。开发者可以在代码中保留断言作为文档,但是应该使它们不会产生代码。如果在包入之前在源文件中定义NDEBUG宏,断言宏将这样简单地定义:#defineassert(cond)((void)0

7、)因此,随后的调用诸如:assert(f!=NULL);扩展为:((void)0);编译器能够优化这个语句,使其根本不会产生代码。可以在包入指令前,将NDEBUG的定义写入到源代码中:#defineNDEBUG#include}这种方法的问题是,每次想打开或者关闭断言的时候必须修改源程序。大多数编译器允许在调用编译器的时候,通过使用命令行自变量来定义宏,通常选择D选项。例如,像下面的命令行出现在源程序的第一行之前,则将断言关断:cc-DNDEBUGget_token.cpilesget_token

8、.casif:#defineNDEBUG使用预处理程序的编译时断言开发者可以使用断言来验证存储器映射结构成员具有正确的尺寸和排列。例如,假设像下面这样为一个定时器定义器件寄存器:typedefstructtimertimer;}structtimer{uint8_tMODE;uint32_tDATA;uint32_tCOUNT;};可以使用一个断言和offsetof宏来验证DATA成员在结构内部具有偏移4,如下:assert(offsetof(timer,DATA)==4);在标准C头文件和标准C

9、++头文件中定义了tffsetof宏。一种fsetof(t,m)形式的表达式从结构类型t的开始处返回成员m的偏移,偏移占若干字节。这个断言确实解决了一个潜在的排列问题,但是并不十分理想。使用断言来检查一个结构成员的偏移将应该在编译时完成的检查延迟到运行时。对断言的调用只可以出现在函数内,因此不得不将调用包含在一个函数里,将这个函数作为程序启动的一部分调用,或者紧接着程序启动调用这个函数。这里需要澄清的是,笔者并不是建议每个断言都可以在编译时检查。例如,像测试一个变量的值的断言如:a

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。