分类 技术志 下的文章

CHECKLIST的不实用之处

CHECKLIST多是类似如下的东西,举一个代码CHECKLIST的例子:

 - 参数的书写是否完整?不要贪图省事只写参数的类型而省略参数名字。
 - 参数命名、顺序是否合理?
 - 参数的个数是否太多?
 - 是否使用类型和数目不确定的参数?
 - 是否省略了函数返回值的类型?
 - 函数名字与返回值类型在语义上是否冲突?
 
我们常常遇到的一个问题就是在进行source peer review的时候是根据每一个CHECK item去从头到尾看一遍代码(如果有50个CHECK items的话,那就从头到尾看50遍代码)还是记住所有CHECK items,然后只看一遍代码,显然我觉得后者在目前实施的可能性是最大的,也是实施最普遍的。

但是效果呢?估计还是看50遍代码较好,但是的确不太具备可操作性,投入的工作量太大,很多人也不会接受。

也有很多人采用折中的方式,比如说一共有10个人参与source peer review,每个人只关注其中的5项check item,然后一起walk through一遍代码。甚至在有些公司采取强制每个人必须能针对自己负责的check item提出问题,否则影响个人绩效之类的方法。

以上是看到公司的一个文档的CHECKLIST时突然想到的,没想出更好的solution。我想可能更多的人是不去记忆Checklist的,而是直接凭经验对代码评头论足的:)

关于宏定义切换以及屏蔽的例子

assert是大家常用的宏,它的用法相信大家都有所了解。P.J Plauger的"The C Standard Library"一书中提到在源代码中切换assert宏定义的方法:
/* turn assertion on */
#undef NDEBUG
#include

/* turn assertions off */
#define NDEBUG
#include

我顺手写了一个例子如下:
/* testmacro1.c */
#define NDEBUG
#include

int main() {

        assert(0); // => ((void)0);

#undef NDEBUG
        #include
        assert(0); // => (void)((0) || (__assert("0", "testmacro.c", 10), 0));
}
测试结果正如P.J Plauger的说明。但仔细看来似乎有些疑惑:总觉得第二个assert也应该展开成((void)0)才对啊。由于NDEBUG被定义,在第一次assert.h展开时,assert就被替换成了((void)0),而后虽然NDEBUG被disable了,但此时由于assert.h的header file guard保护,assert的新定义并没有被重新loaded & evaluated,所以assert似乎依然应该被展开为((void)0),但执行结果却不是。

我自己写了一个程序测试了一下:
/* testmacro1.h */
#ifndef TEST_MACRO1_H
#define TEST_MACRO1_H

#ifdef X_DEBUG
#define x_debug(expr)   ((void)0)
#else
#define x_debug(expr)   #expr
#endif
#endif

/* testmacro1.c */
#define X_DEBUG
#include "testmacro1.h"

int main() {
        x_debug(0); // => ((void)0);

#undef X_DEBUG
        #include "testmacro1.h"
        x_debug(0); // => ((void)0)
}
果不其然,结果正如我所猜测的:
#undef X_DEBUG
#include "testmacro1.h"
并没有改变x_debug的定义,那么第一个例子到底是怎么回事呢?

其实这是C标准库设计所致,打开你所在系统的assert.h标准文件,我在sun solairs 9上是这样的:
#ifndef _ASSERT_H
#define _ASSERT_H
… …
#endif

#undef  assert
#ifdef  NDEBUG
#define assert(EX) ((void)0)
#else
#define assert(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
#endif  /* NDEBUG */

哈哈,这下子看清楚了,原来assert的定义根本不在Header File Guards的保护下,怪不得我思前想后都对不上呢:),因为没有File Guards的保护。使头文件中的宏有机会被重新loaded&envaluated。

下面例子中的第三个assert屏蔽掉了标准库中的assert实现:
/* testmacro3.c */
#define NDEBUG
#include

int main() {

        assert(0); // => ((void)0);

#undef NDEBUG
        #include
        assert(0); // => (void)((0) || (__assert("0", "testmacro3.c", 10), 0));

#define assert(exp) (#exp)
        assert(x==0); // => ("x==0");
}
这种屏蔽很简单,就不多说了,自己看吧。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats