标签 注释 下的文章

只对代码无法表达的东西写注释

本文翻译自”Comments Only What the Code Cannot Say“,来自于《程序员应该知道的97件事》一书中的某个章节。

我们知道理论与实践之间存在差异。在实践中,这个差异远大于其在理论中所描述的那样 – 一份对注释(comments)的观察数据也证实了这一点。理论上,通常的注释代码的想法听起来是值得的:它可以为读者提供更多的细节,可以解释发生了什么事情。有什么能比自我帮助更具可帮助性的呢?然而在实践中,注释却经常变成一个破坏因素。与其他书面形式一样,编写好的注释也是有技巧的。这个技巧的主要内容是知道何时不写注释。

如果代码书写得不合乎语法规范,那么编译器、解释器以及其他一些工具会提出异议。如果代码在某方面功能不正确,评审、静态分析、测试以及在产品环境下的日常使用会发现绝大多数Bug。然而对于注释呢?在《The Elements of Programming Style》一书中KernighanPlauger曾指出“如果注释是错误的,那么它带来的价值就是零(甚至是负值)”。可是就是这样的注释却经常以一种编码错误所不能的方式散布并存活于代码库中。它们会持续不断地分散你的注意力,提供误导信息,细微但却持续地影响着程序员的思维。

那些在技术上没错,但却没有给代码带来任何价值的注释怎么样呢?这类注释简直就是噪音。重复描述代码含义的注释没有为读者提供任何额外价值 – 先用代码表达,再用自然语言复述不能让其看起来更加真实。被注释掉的代码不是可执行代码,所以无论对读者还是对代码运行时它都无法起到任何有用的效果。它自身也会很快地变得陈旧。版本相关的注释以及被注释掉的代码试图解决有关代码版本和历史的问题。但这些问题已经被版本控制工具(更加有效地)解决了。

代码库中普遍存在的噪音类注释以及错误注释助长了程序员们忽略所有注释的行为,他们要么略过注释,要么采取积极措施将注释隐藏起来。程序员是足智多谋的,他们会绕过任何被认为可能会造成破坏的事物:将注释折叠起来;更换颜色样式,使得注释的颜色与背景色相同;编写脚本过滤掉注释。为了使代码库免遭程序员们滥用聪明才智所带来的破坏,降低因忽视真正有价值的注释所带来的风险,我们应该像看待代码那样看待注释。每条注释都应该为读者带来一些价值,否则这些注释就是无用的,应该被删除或重写。

那么,什么才是有价值的呢?注释应该表达那些代码没有表达以及无法表达的东西。如果一段注释被用于解释一些本应该由这段代码自己表达的东西,我们就应该将这段注释看成一个改变代码结构或编码惯例直至代码可以自我表达的信号。我们重命名那些糟糕的方法和类名,而不是去修补。我们选择将长函数中的一些代码段抽取出来形成一些小函数,这些小函数的名字可以表述原代码段的意图,而不是对这些代码段进行注释。尽可能的通过代码进行表达。你通过代码所能表达的和你想要表达的所有事情之间的差额将为注释提供了一个合理的候选使用场合。对那些代码无法表达的东西进行注释,而不要仅简单地注释那些代码没有表达的东西。

By Kevlin Henney

多行宏定义中的注释问题

早上在写代码时遇到这样一个问题:即如何在一个拥有多行的宏定义中做注释?,这里把方法演化的过程贴出来,可能对某些朋友有些借鉴意义。

宏定义高深莫测,而且是比较细节的东西,详细说明请参见"C参考手册"之类的书籍。

在我的代码中,我大致要做这样一个简单的事情:printf("%s%s%s\n", "hello", "macro", "yeah!"); "%s%s%s\n"这个字符串中每一项输出都有一定的含义,而且在真实代码里,这个串中的输出项可不止3个,所以一个直接的想法就是将其定义为一个宏。

#define STR_OUTPUT_FORMAT_V0  "%s%s%s\n"
printf(STR_OUTPUT_FORMAT_V0, "hello ", "macro, ", "yeah!");
程序输出:hello macro, yeah!

由于真实代码中这个串很长,所以打算美化一下格式,定义成下面的样子:
#define STR_OUTPUT_FORMAT_V1  "%s\
                               %s\
                               %s\n"
printf(STR_OUTPUT_FORMAT_V1, "hello ", "macro, ", "yeah!");
程序输出:hello                                macro,                                yeah!

这样的定义显然不对,也在我意料之中,续行符将空格也续到格式串中了,导致输出的结果中带有大量空格。

改进一下,利用C语言的字符串自动连接语法。
#define STR_OUTPUT_FORMAT_V2  "%s"\
                              "%s"\
                              "%s\n"
printf(STR_OUTPUT_FORMAT_V2, "hello ", "macro, ", "yeah!");
程序输出:hello macro, yeah!

现在的问题是如何在这样一个多行的宏定义里加入注释,字段含义特殊,加上注释有利于以后维护以及别人阅读你的代码,否则一堆%s%s,让人看了就头痛。先这么加试试:
#define STR_OUTPUT_FORMAT_E1  "%s"\   /* comment1 */
                              "%s"\   /* comment2 */
                              "%s\n"  /* comment3 */
printf(STR_OUTPUT_FORMAT_E1, "hello ", "macro, ", "yeah!");
我们得到的结果:编译错误。
通过gcc -E 选项我们看到,宏替换后的代码:
                              "%s"\
                              "%s\n"
int main() {
        printf("%s"\, "hello ", "macro, ", "yeah!");
}

由于没有续行符在注释前面,所以宏定义的后两行实际上并没有被包含在宏定义中,就像没有暂住证的人一样,被GCC这个"警察"逮个正着。

继续改进:
#define STR_OUTPUT_FORMAT_V3  "%s"   /* comment1 */ \
                              "%s"   /* comment2 */ \
                              "%s\n"  /* comment3 */
printf(STR_OUTPUT_FORMAT_V3, "hello ", "macro, ", "yeah!");
程序输出:hello macro, yeah!
显然预编译器忽略宏定义中的注释以及空格,STR_OUTPUT_FORMAT_V3就完全符合我的要求了。

当然,很多人不建议使用宏,特别是C++的Fans,宏也的确有很多弊端,这里也有替代方法:
const char *str_output_format = "%s"    /* comment1 */
                                 "%s"    /* comment2 */
                                 "%s\n"; /* comment3 */
printf(str_output_format, "hello ", "macro, ", "yeah!");
程序输出:hello macro, yeah!

用一个字符串变量代替格式宏,还可以避免上述由于在宏中做注释带来的一系列问题。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 Go语言精进之路1 Go语言精进之路2 Go语言第一课 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