第二章:Documenting the code
特殊的注释
一种特殊的注释是带有一些额外标记的C/C++注释块,这样doxygen就知道需要将其加入到文档中了。
对于每个代码块都有两种注释,这两种注释组成了文档:一种是brief 描述另一种是detailed 描述,都是可选的。可以有多于一个的brief 描述和detailed 描述,但是是无效的。
顾名思义,一个brief描述只有一行,而detail描述则是更长更详尽的文档。
有几种方式添加一个detail描述:
1. 使用JavaDoc风格,包含一个C风格的注释块
/**
* ... text ...
*/
2. 使用Qt风格
/*!
* ... text ...
*/
这中间的*都是可选的,因此
/*!
... text ...
*/
也是有效的
3. 第三种风格是至少使用两个C++注释行,每行加多一个/或者是!
///
/// ... text ...
///
或
//!
//!... text ...
//!
4. 有些人喜欢将注释变得比较醒目,可以这样来作
/
/// ... text ...
/
有以下方式添加brief注释
1. 一种是在上述注释块中使用\brief,然后一个空行后跟着Detail注释
/*! \brief Brief description.
* Brief description continued.
*
* Detailed description starts here.
*/
2. 如果配置文件中JAVADOC_AUTOBRIEF被设为YES,则使用JavaDoc风格注释块将自动开始一个brief注释,这个注释将以“.”后跟一个空格或新行结束
/** Brief description which ends at this dot. Details follow
* here.
*/
同样可以应用到多行的C++风格注释中
/// Brief description which ends at this dot. Details follow
/// here.
3. 第三种可以使用一种特殊的C++风格注释,每次不超过一行
/// Brief description.
/** Detailed description. */
或
//! Brief descripion.
//! Detailed description
//! starts here.
注意后一个例子中的空行,Doxygen用他来分开brief描述和detail描述。在此情况下JAVADOC_AUTOBRIEF也应设置为NO
如你所见,doxygen很灵活,下面这种写法是非法的
//! Brief description, which is
//! really a detailed description since it spans multiple lines.
/*! Oops, another detailed description!
*/
因为doxygen只允许一个brief和一个detail描述
更进一步,如果一个brief描述在 declaration前,一个在code前,那么将使用declaration前的那个。对于detailed描述也是如此,definition前的那个比declaration前的有高优先级。
这里有一段Qt风格的C++例子:(注意这一段需要仔细研究,改写掉注释宏的代码)
//! A test class.
/*!
A more elaborate class description.
*/
class Test
{
public:
//! An enum.
/*! More detailed enum description. */
enum TEnum {
TVal1, /*!< Enum value TVal1. */
TVal2, /*!< Enum value TVal2. */
TVal3 /*!< Enum value TVal3. */
}
//! Enum pointer.
/*! Details. */
*enumPtr,
//! Enum variable.
/*! Details. */
enumVar;
//! A constructor.
/*!
A more elaborate description of the constructor.
*/
Test();
//! A destructor.
/*!
A more elaborate description of the destructor.
*/
~Test();
//! A normal member taking two arguments and return an integer value.
/*!
\param a an integer argument.
\param s a constant character pointer.
\return The test results
\sa Test(), ~Test(), testMeToo() and publicVar()
*/
int testMe(int a,const char *s);
//! A pure virtual member.
/*!
\sa testMe()
\param c1 the first argument.
\param c2 the second argument.
*/
virtual void testMeToo(char c1,char c2) = 0;
//! A public variable.
/*!
Details.
*/
int publicVar;
//! A function variable.
/*!
Details.
*/
int (*handler)(int a,int b);
};
这些单行注释包括一个brief描述,而multi-line注释块包含一个更详细的描述。
Brief描述包含在class,namespace或file的member的预览中,小号的斜体字(通过将BRIEF_MEMBER_DESC设置为NO可以关掉这些brief描绘)。缺省的brief描述是detailed描述的第一句话(通过将REPEAT_BRIEF设置为NO可以改变此设置)。在Qt风格中brief和detailed都是可选
缺省的,JavaDoc风格的注释块和Qt风格的注释同样有效。这并不是根据JavaDoc规格的,而是注释的第一行被认为是brief描述。要打开此设置,将JAVADOC_AUTOBRIEF设置为YES。用一个“.”来作分隔,或者使用一个“\”:
/** Brief description (e.g.\ using only a few words). Details follow. */
设置JavaDoc style和JAVADOC_AUTOBRIEF为YES:
/**
* A test class. A more elaborate class description.
*/
class Test
{
public:
/**
* An enum.
* More detailed enum description.
*/
enum TEnum {
TVal1, /**< enum value TVal1. */
TVal2, /**< enum value TVal2. */
TVal3 /**< enum value TVal3. */
}
*enumPtr, /**< enum pointer. Details. */
enumVar; /**< enum variable. Details. */
/**
* A constructor.
* A more elaborate description of the constructor.
*/
Test();
/**
* A destructor.
* A more elaborate description of the destructor.
*/
~Test();
/**
* a normal member taking two arguments & return an integer value.
* @param a an integer argument.
* @param s a constant character pointer.
* @see Test()
* @see ~Test()
* @see testMeToo()
* @see publicVar()
* @return The test results
*/
int testMe(int a,const char *s);
/**
* A pure virtual member.
* @see testMe()
* @param c1 the first argument.
* @param c2 the second argument.
*/
virtual void testMeToo(char c1,char c2) = 0;
/**
* a public variable.
* Details.
*/
int publicVar;
/**
* a function variable.
* Details.
*/
int (*handler)(int a,int b);
};
和大多数文档系统不一样,doxygen也允许你将将member注释放在definition之前。这种方式下,注释可以写在.cpp文件中而非.h文件中。这样头文件就显得比较简洁,同时member前也直接有注释。作为一种妥协,brief描述可以放在member的declaration前,detailed描述可以放在definition前。
在members之后添加注释
如果需要为file,struct,union,class或enmu的members添加注释,并且你需要将这些注释放在compound之内,可以考虑将注释块放在member的后面。这样就要在注释块中添加一个“
下面是个例子:
int var; /*!< Detailed description after the member */
这个块在用来在在一个member之后添加一个注释块(Qt风格)
还有一种方式
int var; /**< Detailed description after the member */
或者是
int var; //!< Detailed description after the member
//!<
或者是
int var; ///< Detailed description after the member
///<
多数情况下只是需要在一个member后添加一个brief描述,如下:
int var; //!< Brief description after the member
或者
int var; ///< Brief description after the member
注意这些块有相同的结构,不过是使用了
这里有个使用注释块的例子:
/*! A test class */
class Test
{
public:
/** An enum type.
* The documentation block cannot be put after the enum!
*/
enum EnumType
{
int EVal1, /**< enum value 1 */
int EVal2 /**< enum value 2 */
};
void member(); //!< a member function.
protected:
int value; /*!< an integer value */
};
Click here for the corresponding HTML documentation that is generated by doxygen.
警告:
这些块只能用来给members和parameters注释。不能用来给files,classes,unions,structs,groups,namespaces和enums添加注释。还有下一节中论述的structural commands在这种注释块中被忽略掉了
Documentation at other places
截止目前,我们谈到的注释块都是在file,class或namespace的declaration或definition之前还有是在member的前后。尽管这通常已经达到目的,但有时要将注释放在其他地方。为一个文件添加注释也是有必要的,但是没有“在文件之前”这种地方。Doxygen允许将注释块放在其他的任何地方(也有不允许的:例如函数体内或一个标准的C-style注释块中)。
这样作比较麻烦的是需要在注释块中添加一些structural命令。
Structual commands(像其他的commands)以“\”开头,或是一个“@”(使用JavaDoc风格),后面是命令名和一或多个参数。例如,如果你想给上面的Test类添加一个注释:
/*! \class Test
\brief A test class.
A more detailed class description.
*/
这里特殊命令“\class”用于指出该注释块中含有对Test类的注释。还有一些其他的structural命令:
•\struct to document a C-struct.
•\union to document a union.
•\enum to document an enumeration type.
•\fn to document a function.
•\var to document a variable or typedef or enum value.
•\def to document a #define.
•\file to document a file.
•
amespace to document a namespace.
•\package to document a Java package.
•\interface to document an IDL interface.
参看Special Commands获得更详细资料。
为了注释一个类中的member,首先要对该类作注释。同样的问题上升到namespace。要注释一个全局的function,typedef,enum或preprocessor定义,你需要首先定义包含它的文件(通常情况下是一个.h文件,因为这些文件包含可以export到其他源文件的信息)。
让我们重复一下,因为常常被忽视:要注释一个global objects(functions,typedefs, enum,macros等),必须注释它们所在的.h文件。换句话,至少要这样注释一下
/*! \file */
或这样一个
/** @file */
行在该文件中
这里用个名为structcmd.h的C头文件,讲解如何使用structal commands。
/*! \file structcmd.h
\brief A Documented file.
Details.
*/
/*! \def MAX(a,b)
\brief A macro that returns the maximum of \a a and \a b.
Details.
*/
/*! \var typedef unsigned int UINT32
\brief A type definition for a .
Details.
*/
/*! \var int errno
\brief Contains the last error code.
\warning Not thread safe!
*/
/*! \fn int open(const char *pathname,int flags)
\brief Opens a file descriptor.
\param pathname The name of the descriptor.
\param flags Opening flags.
*/
/*! \fn int close(int fd)
\brief Closes the file descriptor \a fd.
\param fd The descriptor to close.
*/
/*! \fn size_t write(int fd,const char *buf, size_t count)
\brief Writes \a count bytes from \a buf to the filedescriptor \a fd.
\param fd The descriptor to write to.
\param buf The data buffer to write.
\param count The number of bytes to write.
*/
/*! \fn int read(int fd,char *buf,size_t count)
\brief Read bytes from a file descriptor.
\param fd The descriptor to read from.
\param buf The buffer to read into.
\param count The number of bytes to read.
*/
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef unsigned int UINT32;
int errno;
int open(const char *,int);
int close(int);
size_t write(int,const char *, size_t);
int read(int,char *,size_t);
Click here for the corresponding HTML documentation that is generated by doxygen.
Because each comment block in the example above contains a structural command, all the comment blocks could be moved to another location or input file (the source file for instance), without affecting the generated documentation. The disadvantage of this approach is that prototypes are duplicated, so all changes have to be made twice! Because of this you should first consider if this is really needed, and avoid structural commands if possible. I often receive examples that contain \fn command in comment blocks which are place in front of a function. This is clearly a case where the \fn command is redundant and will only lead to problems.
因为上例中每个注释块都包含一个结构化命令,所有注释快都可以放在其他位置或input文件(例如source file),都不会影像文档的生成。这种做法的缺点是原型被复制了,所以每次都要写两遍。因为如此,你应该首先考虑是否有必要,并尽可能避免structural commands。我常常收到含有这种文件,在一个函数前的注释中有“\fn”命令。这样是冗余的,导致容易出错。