代码注释规范-google版本

  • 注释

注释虽然写起来很痛苦,但对保证代码可读性至为重要,下面的规则描述了应该注释什么、注释在哪儿。当然也要记住,注释的确很重要,但最好的代码本身就是文档(self-documenting),类型和变量命名意义明确要比通过注释解释模糊的命名好得多。

注释是为别人(下一个需要理解你的代码的人)而写的,认真点吧,那下一个人可能就是你!

1. 注释风格(Comment Style)

使用// /* */ ,统一就好。

// /* */ 都可以,// 只是用的更加广泛,在如何注释和注释风格上确保统一。

2. 文件注释(File Comments)

在每一个文件开头加入版权公告,然后是文件内容描述。

法律公告和作者信息 :

每一文件包含以下项,依次是:

1) 版权(copyright statement):如Copyright 2008 Google Inc. 

2) 许可版本(license boilerplate):为项目选择合适的许可证版本,如Apache 2.0 、BSD 、LGPL 、GPL ;

3) 作者(author line):标识文件的原始作者。

如果你对其他人创建的文件做了重大修改,将你的信息添加到作者信息里,这样当其他人对该文件有疑问时可以知道该联系谁。

文件内容 :

每一个文件版权许可及作者信息后,都要对文件内容进行注释说明。

通常,.h 文件要对所声明的类的功能和用法作简单说明,.cc 文件包含了更多的实现细节或算法讨论,如果你感觉这些实现细节或算法讨论对于阅读有帮助,可以把.cc 中的注释放到.h 中,并在.cc 中指出文档在.h 中。

不要单纯在.h .cc 间复制注释,复制的注释偏离了实际意义。

3. 类注释(Class Comments)

每个类的定义要附着描述类的功能和用法的注释。

// Iterates over the contents of a GargantuanTable.  Sample usage:

//    GargantuanTable_Iterator* iter = table->NewIterator();

//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {

//      process(iter->key(), iter->value());

//    }

//    delete iter;

class GargantuanTable_Iterator {

  ...

}

如果你觉得已经在文件顶部详细描述了该类,想直接简单的来上一句“完整描述见文件顶部”的话,还是多少在类中加点注释吧。

如果类有任何同步前提(synchronization assumptions),文档说明之。如果该类的实例可被多线程访问,使用时务必注意文档说明。

4. 函数注释(Function Comments)

函数声明处注释描述函数功能,定义处描述函数实现。

函数声明 :

注释于声明之前,描述函数功能及用法,注释使用描述式("Opens the file")而非指令式("Open the file");注释只是为了描述函数而不是告诉函数做什么。通常,注释不会描述函数如何实现,那是定义部分的事情。

函数声明处注释的内容:

1) inputs(输入)及outputs(输出);

2) 对类成员函数而言:函数调用期间对象是否需要保持引用参数,是否会释放这些参数;

3) 如果函数分配了空间,需要由调用者释放;

4) 参数是否可以为NULL 

5) 是否存在函数使用的性能隐忧(performance implications);

6) 如果函数是可重入的(re-entrant),其同步前提(synchronization assumptions)是什么?

举例如下:

// Returns an iterator for this table.  It is the client's

// responsibility to delete the iterator when it is done with it,

// and it must not use the iterator once the GargantuanTable object

// on which the iterator was created has been deleted.

//

// The iterator is initially positioned at the beginning of the table.

//

// This method is equivalent to:

//    Iterator* iter = table->NewIterator();

//    iter->Seek("");

//    return iter;

// If you are going to immediately seek to another place in the

// returned iterator, it will be faster to use NewIterator()

// and avoid the extra seek.

Iterator* GetIterator() const

但不要有无谓冗余或显而易见的注释,下面的注释就没有必要加上“returns false otherwise”,因为已经暗含其中了:

// Returns true if the table cannot hold any more entries.

bool IsTableFull()

注释构造/析构函数时,记住,读代码的人知道构造/析构函数是什么,所以“destroys this object”这样的注释是没有意义的。说明构造函数对参数做了什么(例如,是否是指针的所有者)以及析构函数清理了什么,如果都是无关紧要的内容,直接 省掉注释,析构函数前没有注释是很正常的。

函数定义 :

每个函数定义时要以注释说明函数功能和实现要点,如使用的漂亮代码、实现的简要步骤、如此实现的理由、为什么前半部分要加锁而后半部分不需要。

不要从.h 文件或其他地方的函数声明处直接复制注释,简要说明函数功能是可以的,但重点要放在如何实现上。

5. 变量注释(Variable Comments)

通常变量名本身足以很好说明变量用途,特定情况下,需要额外注释说明。

类数据成员 :

每个类数据成员(也叫实例变量或成员变量)应注释说明用途,如果变量可以接受NULL 或-1等警戒值(sentinel values),须说明之,如:

private:

 // Keeps track of the total number of entries in the table.

 // Used to ensure we do not go over the limit. -1 means

 // that we don't yet know how many entries the table has.

 int num_total_entries_

全局变量(常量) :

和数据成员相似,所有全局变量(常量)也应注释说明含义及用途,如:

// The total number of tests cases that we run through in this regression test.

const int kNumTestCases = 6

6. 实现注释(Implementation Comments)

对于实现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释。

代码前注释 :

出彩的或复杂的代码块前要加注释,如:

// Divide result by two, taking into account that x

// contains the carry from the add.

for (int i = 0; i < result->size(); i++) {

  x = (x << 8) + (*result)[i];

  (*result)[i] = x >> 1;

  x &= 1;

}

行注释 :

比较隐晦的地方要在行尾加入注释,可以在代码之后空两格加行尾注释,如:

// If we have enough memory, mmap the data portion too.

mmap_budget = max<int64>(0, mmap_budget - index_->length());

if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock))

  return;  // Error already logged.

注意,有两块注释描述这段代码,当函数返回时注释提及错误已经被记入日志。

前后相邻几行都有注释,可以适当调整使之可读性更好:

...

DoSomething();                  // Comment here so the comments line up.

DoSomethingElseThatIsLonger();  // Comment here so there are two spaces between

                                // the code and the comment.

...

NULL、true/false、1、2、3…… :

向函数传入、布尔值或整数时,要注释说明含义,或使用常量让代码望文知意,比较一下:

bool success = CalculateSomething(interesting_value,

                                  10,

                                  false,

                                  NULL);  // What are these arguments??

和:

bool success = CalculateSomething(interesting_value,

                                  10,     // Default base value.

                                  false,  // Not the first time we're calling this.

                                  NULL);  // No callback.

使用常量或描述性变量:

const int kDefaultBaseValue = 10;

const bool kFirstTimeCalling = false;

Callback *null_callback = NULL;

bool success = CalculateSomething(interesting_value,

                                  kDefaultBaseValue,

                                  kFirstTimeCalling,

                                  null_callback);

不要 :

注意永远不要用自然语言翻译代码作为注释,要假设读你代码的人C++比你强:D:

// Now go through the b array and make sure that if i occurs,

// the next element is i+1.

...        // Geez.  What a useless comment.

7. 标点、拼写和语法(Punctuation, Spelling and Grammar)

留意标点、拼写和语法,写的好的注释比差的要易读的多。

注释一般是包含适当大写和句点(.)的完整的句子,短一点的注释(如代码行尾的注释)可以随意点,依然要注意风格的一致性。完整的句子可读性更好,也可以说明该注释是完整的而不是一点不成熟的想法。

虽然被别人指出该用分号(semicolon)的时候用了逗号(comma)有点尴尬。清晰易读的代码还是很重要的,适当的标点、拼写和语法对此会有所帮助。

8. TODO注释(TODO Comments)

对那些临时的、短期的解决方案,或已经够好但并不完美的代码使用TODO 注释。

这样的注释要使用全大写的字符串TODO ,后面括号(parentheses)里加上你的大名、邮件地址等,还可以加上冒号(colon):目的是可以根据统一的TODO 格式进行查找:

// TODO(kl@gmail.com): Use a "*" here for concatenation operator.

// TODO(Zeke) change this to use relations.

如果加上是为了在“将来某一天做某事”,可以加上一个特定的时间("Fix by November 2005")或事件("Remove this code when all clients can handle XML responses.")。

______________________________________

译者:注释也是比较人性化的约定了:

1. 关于注释风格,很多C++的coders更喜欢行注释,C coders或许对块注释依然情有独钟,或者在文件头大段大段的注释时使用块注释;

2. 文件注释可以炫耀你的成就,也是为了捅了篓子别人可以找你;

3. 注释要言简意赅,不要拖沓冗余,复杂的东西简单化和简单的东西复杂化都是要被鄙视的;

4. 对于Chinese coders来说,用英文注释还是用中文注释,it is a problem,但不管怎样,注释是为了让别人看懂,难道是为了炫耀编程语言之外的你的母语或外语水平吗;

5. 注释不要太乱,适当的缩进才会让人乐意看,但也没有必要规定注释从第几列开始(我自己写代码的时候总喜欢这样),UNIX/LINUX下还可以约定是使用tab还是space,个人倾向于space;

6. TODO很不错,有时候,注释确实是为了标记一些未完成的或完成的不尽如人意的地方,这样一搜索,就知道还有哪些活要干,日志都省了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
别的不多说了 非常好的东西 等待有缘人 摘录目录如下 Google C++ 风格指南 - 中文版 目录 译者前言 背景 1. 头文件 1.1. #define 保护 1.2. 头文件依赖 1.3. 内联函数 1.4. -inl.h文件 1.5. 函数参数的顺序 1.6. #include 的路径及顺序 译者 (YuleFox) 笔记 2. 作用域 2.1. 名字空间 2.1.1. 匿名名字空间 2.1.2. 具名的名字空间 2.2. 嵌套类 2.3. 非成员函数, 静态成员函数, 和全局函数 2.4. 局部变量 2.5. 静态和全局变量 译者 (YuleFox) 笔记 3. 类 3.1. 构造函数的职责 3.2. 默认构造函数 3.3. 显式构造函数 3.4. 拷贝构造函数 3.5. 结构体 VS. 类 3.6. 继承 3.7. 多重继承 3.8. 接口 3.9. 运算符重载 3.10. 存取控制 3.11. 声明顺序 3.12. 编写简短函数 译者 (YuleFox) 笔记 4. 来自 Google 的奇技 4.1. 智能指针 4.2. cpplint 5. 其他 C++ 特性 5.1. 引用参数 5.2. 函数重载 5.3. 缺省参数 5.4. 变长数组和 alloca() 5.5. 友元 5.6. 异常 5.7. 运行时类型识别 5.8. 类型转换 5.9. 流 5.10. 前置自增和自减 5.11. const 的使用 5.12. 整型 5.13. 64 位下的可移植性 5.14. 预处理宏 5.15. 0 和 NULL 5.16. sizeof 5.17. Boost 库 6. 命名约定 6.1. 通用命名规则 6.2. 文件命名 6.3. 类型命名 6.4. 变量命名 6.5. 常量命名 6.6. 函数命名 6.7. 名字空间命名 6.8. 枚举命名 6.9. 宏命名 6.10. 命名规则的特例 7. 注释 7.1. 注释风格 7.2. 文件注释 7.3. 类注释 7.4. 函数注释 7.5. 变量注释 7.6. 实现注释 7.7. 标点, 拼写和语法 7.8. TODO 注释 译者 (YuleFox) 笔记 8. 格式 8.1. 行长度 8.2. 非 ASCII 字符 8.3. 空格还是制表位 8.4. 函数声明与定义 8.5. 函数调用 8.6. 条件语句 8.7. 循环和开关选择语句 8.8. 指针和引用表达式 8.9. 布尔表达式 8.10. 函数返回值 8.11. 变量及数组初始化 8.12. 预处理指令 8.13. 类格式 8.14. 初始化列表 8.15. 名字空间格式化 8.16. 水平留白 8.17. 垂直留白 译者 (YuleFox) 笔记 9. 规则特例 9.1. 现有不合规范代码 9.2. Windows 代码 10. 结束语

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值