免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: criticalstrike
打印 上一主题 下一主题

[其他] 大家会对每个子程序做输入参数的检查吗? [复制链接]

论坛徽章:
0
11 [报告]
发表于 2013-10-22 15:10 |只看该作者

t

本帖最后由 slimzhao 于 2013-10-22 15:10 编辑

看情况而定. 应该在模块/子系统/数据入口/信任的边界作检查. 可以说不适宜对任何一个子程序作检查, 更不适宜不作检查. 程序规模越大, 这种检查的防御作用越明显.

简单地说"作检查"是不精确的, 比如assert是一种检查, 用if 语句判断某个条件, 条件不满足时抛出异常也是一种检查, 这两种类型的检查的目的和在软件开发整个生命周期中的作用
是不同的.

对于assert, 首先它是标准C库中的一部分, 强烈建议使用. 不同的编译器/平台的实现会在assert失败时, 有不同的实现, 比如可以在控制台上输出失败的条件表达式, 然后调用abort退出程序, 也可以弹出
一个错误对话框.  assert所断言的, 是程序设计过程中by design的约束, 如果断言失败, 说明程序的调用者与被调用者没有遵循共同的约定, 或在运行时的某个时间点没有满足某些不变式(Meyer"s Design by contract).
程序员一旦发现assert失败, 应该做的事是修改程序. 没有例外.


if (ptr == NULL) {
      throw runtime_error("null pointer");
}
这种类型的代码, 应该是调用者和被调用者之间接口的一部分(没错, 异常应该是函数接口的一部分, 而不是可以可以事后考虑/修补的事), 是程序设计中可能的执行路径中的一条. 执行流走到这一步, 并不意味着程序一定就出错了.
只要调用者能妥善地处理抛出的异常. 程序还是有可能继续正常运行的.

作检查的子程序, 越是面向更大的调用者, 越应该对入口参数作检查. 比如C/C++中某个源文件内部的 static函数, 可以不作检查, 但放在.h 中声明的函数原型, 如果是给当前组件之外的调用者调用的, 应该作检查, 如果是仅仅给
当前组件/项目内部的其它.cpp调用的, 可以不作检查.

这里判断的要点是确定一个可维护的代码量/信任边界. 为什么在函数内部的static 函数往往不作检查, 是因为一般推荐的文件大小控制在500行左右, 而static函数只可能被当前文件内的代码调用, 这是一个程序员可以合理理解/维护的
代码量.  为什么说在当前组件/项目(可以想象成Visual studio中的一个项目)内部的调用的函数可做可不作检查呢, 这是因为项目可大可小, 如果项目小到一个程序员可以合理地理解/维护的规模, 你可以不做检查.

如果调用者和被调用者是由不同的程序员写的, 基本上应该作检查, 不管你的合作者多么牛B, 不要信任调用者, 智者千虑必有一失. 再则, 牛B会离职被新人顶替.

附带说一下, 如果.h文件中你有详细的doxygen注释, 言之凿凿地写明了什么样的参数才是合法的, 我要赞一下你的接口设计真是讲究, 但这仍然不能代替assert和运行时检查, 前者是鼓励你正确的事, 后者是防止你做错误的事. 两手都要抓, 两手都要硬.

在面向对象代码中, 不光是子程序入口处应该作检查, 在子程序返回时也应该作检查, 一是对子程序的后条件作检查, 看是否实现了子程序对调用者的承诺, 另一则是维持当前对象本身的不变性, 以保证对象自身状态是良好定义的.

Herb Sutter项目在他的一本书(具体哪本我忘了)中写了一个通用的类, 利用C++的RAII/RRID机制(Resource Acquisition is Initialization, Resource Release is destruction) 用来做invariant检查.

assert的滥用, 象楼上所说, 的确会让程序显得混乱, 多数这样的检查也是冗余的. 另外, assert运行时也会拖慢程序, 虽然release版这个宏会化为乌有.

如果你的程序在正确地地方, 正确的时机用上了正确的assert, 往往也只是好的实践的一种表象.  我见过一些代码, 虽然用好了assert, 却没有在测试中让执行流真正地流经每一个assert, 而在release版本中, 它们又都消失了, 所以最终产品也没机会
发挥assert的作用, assert的使用, 不是一次性静态地摆在代码里就完整了的, 它不仅仅是一行代码, 更是一个过程.

有些书中(具体我就不点名了), 说定义了DEBUG这个宏时 assert才会定义为真正的检查语句, 实际情况是, 定义了NDEBUG这个宏时, assert才会被定义为空. 可以通过检查一个新生成的VC项目的Debug/Release两种配置来验证这一点.

assert的条件表达式中, 切不可放入程序正常运行时必需执行到的表达式, 尤其是函数调用, 这个坑, 我不止一次掉进去过.

论坛徽章:
0
12 [报告]
发表于 2013-10-22 15:57 |只看该作者
assert 只有为debug 时才很有用,在发行版里,该错的还是错,我见到过有一些人甚至不提倡用 assert 做检查,我个人拙见,向外提供的接口,尽可能的详尽的检查参数的正确性,在内部子函数,全部以static 函数定义,这样子程序的只保证被接口函数的内部使用,这样内部的子函数参数检查是几乎不或者很少需要检查的。

以上为个人拙见..............
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP