有时我想写一个“主要”注释来描述一大块代码,然后写一个“次要”注释来描述该代码块中的几行:
// Major comment
// Minor comment
...
// Minor comment 2
...
主要注释下面没有代码看起来很奇怪,你无法直观地看出它下面描述了多少代码。
你如何看待这些评论?
(我记得不久前在 Code Complete 中读到过这个,但我不拥有这本书。)
有时我想写一个“主要”注释来描述一大块代码,然后写一个“次要”注释来描述该代码块中的几行:
// Major comment
// Minor comment
...
// Minor comment 2
...
主要注释下面没有代码看起来很奇怪,你无法直观地看出它下面描述了多少代码。
你如何看待这些评论?
(我记得不久前在 Code Complete 中读到过这个,但我不拥有这本书。)
我对“主要”评论使用多行评论:
/*
* yada yada yada
*/
并为次要的使用单行注释。
我知道有些人不喜欢使用 /* */ 样式的注释,因为它使自动注释和取消注释块变得更加困难......但我喜欢它们的外观,并且我坚信代码应该在美学上令人愉悦读。
这也意味着您应该能够在很大程度上解析代码的结构而无需阅读细节,这意味着我倾向于使用相当多的空格和分隔注释行来帮助分解。因此,对于我想评论的块,我可能会写:
/**
* detailed description ...
*/
code
// -- minor comment
code
code
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
//主要评论 // ------------- ... // 小注释 ... ... // 次要注释(行尾)
我将主要注释放在代码(块)上方,前面有一个空行,有时全部大写。我把一些小评论放在右边,缩进到第 81 列,以免它们妨碍代码。这两个都使用 //。
对于算法“话语”,我使用 /* */ ,如下所示:
/*
* This is a long discourse on the code which follows it, usually
* placed at the beginning of a method and containing information
* which is not appropriate for the doc comments.
*/
我认为“主要”和“次要”评论之间的区别在于它们所附加的程序结构。例如,我将方法或类级别的文档注释视为“主要”,将块或行级别的注释视为“次要”:
/**
* This is major comment describing the method
*/
public void foo() {
if (...) {
// minor comment describing block
...
doSomething(); // minor comment describing line
}
}
与其用注释来分割你的代码,我认为用描述性名称和文档注释将功能单元重构为它们自己的方法是一种很好的做法。
这一切都以 C 为中心。在 C/C++ 中,我倾向于编写
/* file -- what it is -*-emacs magic-*- */
作为第一行。
/*
* Block comments like this
*/
if( I need a comment on a code block) {
/* I tend to write them like this */
x = x + 1 ; /* ... and write my */
/* line comments so */
}
我通常保留// comments
内部代码,并将好的旧 BSD 注释保留在块注释中。
在 Lisp 中
;;;; Four semicolons for "file-scope" comments
;;; Three for block comments over a large chunk of code
(defun quux (foo bar)
"Don't forget your docstrings, folks"
;; but big code comments get two semicolons
(let ((a 1)
(b 2)) ; and only one semicolon
(+ a b))) ; means an in-line comment.
# comment languages like Python and Ruby
# Have to live with one style of comment.
def quux(a,b):
return a + b # poor neglected things.
我通常/* */
在每个部分的顶部使用注释代码块。我不使用内联注释,除非在特殊情况下(例如棘手的代码),因为我觉得注释是“隐藏的”,并且代码可以稍后扩展,并且必须对注释进行微管理。例如:
int parseEverything()
{
/* Initialize the parser. */
random_code_here();
still_more_init();
/// (Note: the above line still falls under the init section, even if it's separated by a newline.)
/* Main parser loop. */
while(!done_parsing) {
/* Grab the token. */
if(x) {
/* Preprocessor stuff. */
y();
} else {
/* Normal token. */
z();
}
/* Insert into tree. */
make_tree_node();
insert_into_tree();
/* Move to next token. */
++streamPtr;
/// (Note: the above could be expanded to take up multiple lines, thus
/// if an inline comment were used it'd have to be moved, if
/// you even remember there's a comment there.)
}
clean_up();
}
当然,如果代码很明显,则不需要注释,如clean_up()
. 包括注释并没有太大的伤害,如果稍后扩展,它会更容易知道在哪里放置额外的清理代码。
使用这个方案,我发现仅仅通过它的注释就可以很容易地跟踪一个函数。 parseEverything
包含三个主要部分:初始化、主循环和清理。在主循环中,我们抓取令牌(预处理器或普通),将其插入树中,然后继续下一个令牌。
很可能每个部分都需要自己的 [set] 函数,因此很明显,如果部分变得庞大,您可能需要重构。
我应该补充一点,我这样格式化多行注释(我的“IDE”( )使用默认脚本(对于我的发行版)为我在每一行Vim
插入,这很方便):*
/*
* This is a comment which normally would be on one line, but is either split into multiple
* lines for emphasis or so we don't have 160-character hard-to-read comments everywhere.
*/
另外,我评论#else
's 和#endif
's:
#ifndef FOO_H
#define FOO_H
#ifdef DEBUG
#else /* DEBUG */
#endif /* !DEBUG */
#endif /* FOO_H */
但这有点跑题了。
(#include
守卫不需要not
(!
)在它们之前,因为它们的使用是显而易见的,这是传统。=])
我使用这样的东西,使它看起来更像是以下代码块的“标题”或分隔符:
// ***** Major comment *****
// Minor comment
...
// Minor comment 2
...
当然,这是假设“主要评论”只是几句话
我可能会这样做:
// Here we do it
//
// So, be aware this text is just to make a silly
// long comment to show how it would look like
// in real code.
doTheRealThing();
// and this is another thingy
doOtherThing();
如果注释记录了出现在其他代码块之间的一些代码,并且我想真正弄清楚注释所指的位置,有时我会发现我在这些东西周围写块
// prepare for party
doIt();
// Here we do it
//
{
// So, be aware this text is just to make a silly
// long comment to show how it would look like
// in real code.
doTheRealThing();
// and this is another thingy
doOtherThing();
}
// another code that is not really affected by the comment
// above
die();
有时,块需要自己的一组局部变量来完成任务,然后块还可以将它们的范围缩小到需要它们的地方。可以说,此类代码应该放入各自的函数中,但偶尔会发生这样做会降低代码质量。现在,对于注释方法,我通常只在它们的头文件中注释它们,并通过以下方式进行:
/**
* This function will return the current object.
*
* And now it follows the normal long stuff that's again
* a bit stretched to fill space...
*/
Object getCurrentObject();
对于取消注释的代码范围,我明确不使用这些注释,因为我只保留它们以记录代码。我会用
#if 0
Code in Here that's disabled
#endif
它还可以让我免于使用一些无效的 C++ 代码(这些分隔符之间的东西仍然必须包含有效的标记)。不过,我不确定 C# 中的情况如何。
// A plate is displayed if a WorkFlowStepUpdate message is received
// whose:
// * Change_Type is License_No
// * Event_Type is GA, NA, or NG
// * New_Value is non-null and non-blank
// * Inspection_DateTime<(NOW-TimeInMinutesBeforeExpiringDisplaySignMessage)
//
// A plate is removed:
// * if it has been displayed for TimeInMinutesBefore...
// * a GA, NA, or NG CloseEvent is received whose New_Value matches
// a displayed plate
//
// If a plate is to be added to a full screen, the oldest plate on the display
// is removed to make room for the new plate.
.
.
.
.
.
// Record the ping status of each IP device
foreach (string s in th.Keys)
{
// We don't know if this is a wks or svr.
// But we can rely on 0 being bad, and we'll
// get the 'proper' state enumeration down in GetsOHInfo
//
if (IsItLive(s)) IPStates[s] = 1;
else IPStates[s] = 0;
IPTimes[s] = System.DateTime.Now.ToUniversalTime();
}
主要评论
/*** Function - fooBar() ****************************
** Description **
** does the flooble using the bardingle algorithm **
** with the flinagle modification **
** Pre-condition **
** all moths are unballed **
** Post-condition **
** all moths are balled **
******************************************************/
void fooBar( int foo ) {
...
...
}
/*** Function - fooBar() END ***********************/
小评论
// note cast to int to ensure integer maths result
int i = (int)y / (int)x;
// Top-level (major) comment
theThing=doSomething();
// - Second-level (minor) comment
anotherThing=doSomethingWith(theThing);
// - - Third-level (minor-minor?) comment
yetAnotherThing=doSomethingWith(anotherThing);
// - Back to second level
destroy(anotherThing);
// Back to first level
helloWorld();
当然,当语法不允许时,识别技巧不适用(阅读:Python)
这是我的评论风格偏好:
/**
* This is a comment explaining
* what this method is actually doing
*/
public void foo()
{
// this is a simple comment
doSomething();
// this is a special comment
// explaining thoroughly what I'm doing
// using as many words as possible
// to be the most concise
doSomethingSpecial();
}