在编写大量代码时,或者与多人协作进行开发时,文字记录很重要(文档或注释),尤其对于开发者本人回顾之前写过的代码和 code reviewer 查看。目前,代码中的注释进是程序员们最经常使用的记录方法。但是,由于每个人的注释风格不同,有些开发者甚至对API并不进行任何注释描述,导致很多影响生产效率的问题,也增加了软件维护的成本。很多人对于怎样写注释也会困惑和反感。因此,使用一些代码文档工可以帮助这个开发流程高效、规范地进行。
使用这种工具我个人认为最大的帮助是可以节省时间,并提高生产力:
- 不用去构思如何去写注释,用哪一种风格去写,从而专注于构思代码。
- 减少看其他人代码的时间成本。
Doxygen 就是这样一种编写软件参考文档的工具。该文档是直接以注释的形式写在代码中的,因此比较容易修改和查看。而且对于代码里的注释,Doxygen还可以为C++项目生成html,Latex和PDF的文档。
虽然使用过Doxygen的开发者可能并不会经常阅读由Doxygen生成的那些文档,而是更加倾向于阅读源代码里的注释。但是并不妨碍Doxygen成为一款很受欢迎而且高效的代码注释工具,至少我个人很喜欢Doxygen对于注释的种种规范。
关于如何使用Dxygen的适用方法,可以参照官方的教程,不会有比这个更加权威并且详细的说明了:https://www.doxygen.nl/manual/index.html。
在之前分享过的C/C++ Coding Style(https://zhuanlan.zhihu.com/p/267645803)中,我介绍了使用Doxygen进行代码注释的一些风格,在这里详细介绍一些我经常使用的Doxygen属性。
一个例子
例如一个头文件中:
/*****************************************************************************
* Portfolio Info
****************************************************************************/
/**
* @file doxygen.h
* @brief File containing example of doxygen usage for quick reference.
*
* Here typically goes a more extensive explanation of what the header
* defines. Doxygens tags are words preceeded by either a backslash @\\
* or by an at symbol @@.
*
* @author Chris Wu
* @date 24 Oct 2019
* @see <http://www.doxygen.nl/manual/index.html>
*/
/** @addtogroup DOXYGEN_API
* @brief Doxygen api example.
*
* Detailed api description.
*
* @{
*/
#ifndef _TEMP_DOXYGEN_H
#define _TEMP_DOXYGEN_H
#ifdef __cplusplus
extern "C" {
#endif
/* INCLUDE FILES */
#include <stdint.h>
//#include <system_header2.h>
//#include "local_header1.h"
//#include "local_header2.h"
/* GLOBAL DEFINES */
/**
* @brief Use brief, otherwise the index won't have a brief explanation.
*
* Detailed explanation.
*/
typedef enum eEnumMode
{
ENUM_FIRST, /**< Some documentation for first. */
BOXENUM_SECOND, /**< Some documentation for second. */
BOXENUM_ETC /**< Etc. */
} tEnumMode;
/**
* @brief Use brief, otherwise the index won't have a brief explanation.
*
* Detailed explanation.
*/
typedef struct BoxStruct
{
int a; /**< Some documentation for the member BoxStruct#a. */
int b; /**< Some documentation for the member BoxStruct#b. */
double c; /**< Etc. */
} tBoxStruct;
/* GLOBAL VARIABLES */
extern int giValue;
/* GLOBAL FUNCTIONS */
/**
* @brief Example showing how to document a function with Doxygen.
*
* Description of what the function does. This part may refer to the parameters
* of the function, like @p param1 or @p param2. A word of code can also be
* inserted like @c this which is equivalent to <tt>this</tt> and can be useful
* to say that the function returns a @c void or an @c int. If you want to have
* more than one word in typewriter font, then just use @<tt@>.
* We can also include text verbatim,
* when the language is not the one used in the current source file (but
* <b>be careful</b> as this may be supported only by recent versions
* of Doxygen). By the way, <b>this is how you write bold text</b> or,
* if it is just one word, then you can just do @b this.
*
* @param [in] param1 Description of the first parameter of the function.
* @param [out] param2 The second one, which follows @p param1, and represents output.
*
* @return Describe what the function returns.
* @retval XXX_OK if successful.
*
* @see doxygen_theSecondFunction
* @see Box_The_Last_One
* @see <http://website/>
* @note Something to note.
* @warning Warning.
*/
int doxygen_theFirstFunction(int param1, int param2);
/**
* @brief A simple stub function to show how links do work.
*
* Links are generated automatically for webpages (like <http://www.google.com>)
* and for structures, like sBoxStruct. For typedef-ed types use
* #tBoxStruct.
* For functions, automatic links are generated when the parenthesis () follow
* the name of the function, like doxygen_theFirstFunction().
* Alternatively, you can use #doxygen_theFirstFunction.
* @return @c NULL is always returned.
*/
void doxygen_theSecondFunction(void);
#ifdef __cplusplus
}
#endif
#endif /* _TEMP_DOXYGEN_H */
/** @}*/
版权声明注释
/*****************************************************************************
* Portfolio Info
****************************************************************************/
我会把项目的版权声明信息放在这。
文件描述注释
/**
* @file header.h
* @brief Brief file introduction.
*
* Detailed file introduction.
*
* @author Name
* @date day month year
* @see Related link.
*/
在这里列出这个文件的名字,和一些基本信息:
- @file: 文件名
- @brief:文件一句话介绍
- @author:文件作者
- @date:修改日期
- @see:额外的一些参考信息,比如有用过的链接
API Group
/** @addtogroup DOXYGEN_API
* @brief Doxygen api example.
*
* Detailed api description.
*
* @{
*/
- API codes…
/** @}*/
这两段代码搭配使用,一前一后,中间包含API代码。这部分定义了这个文件的API group,可以在Doxygen生成的文件中查看到其中包含的所有API group(比如变量,类,函数)信息。
变量前的注释
/**
* @brief Use brief, otherwise the index won't have a brief explanation.
*
* Detailed explanation.
*/
typedef struct BoxStruct
{
int a; /**< Some documentation for the member BoxStruct#a. */
int b; /**< Some documentation for the member BoxStruct#b. */
double c; /**< Etc. */
} tBoxStruct;
对于一些需要说明的变量,可以在变量前加上一段Doxygen注释,方便度代码的人查看,也可以声称在比如HTML等文档中。
API 函数注释
/* GLOBAL FUNCTIONS */
/**
* @brief Example showing how to document a function with Doxygen.
*
* Description of what the function does. This part may refer to the parameters
* of the function, like @p param1 or @p param2. A word of code can also be
* inserted like @c this which is equivalent to <tt>this</tt> and can be useful
* to say that the function returns a @c void or an @c int. If you want to have
* more than one word in typewriter font, then just use @<tt@>.
* We can also include text verbatim,
* when the language is not the one used in the current source file (but
* <b>be careful</b> as this may be supported only by recent versions
* of Doxygen). By the way, <b>this is how you write bold text</b> or,
* if it is just one word, then you can just do @b this.
*
* @param [in] param1 Description of the first parameter of the function.
* @param [out] param2 The second one, which follows @p param1, and represents output.
*
* @return Describe what the function returns.
* @retval XXX_OK if successful.
*
* @see doxygen_theSecondFunction
* @see Box_The_Last_One
* @see <http://website/>
* @note Something to note.
* @warning Warning.
*/
int doxygen_theFirstFunction(int param1, int param2);
对于所有头文件的函数,都需要进行函数注释。
- @param:标记变量 [in] [out]表示输入输出方向
- @return:返回值描述
- @retval:具体返回值及其含义
- @see:link信息
- @note:备注信息
- @warning:需要函数使用者注意的信息,比如:功能未经完全验证
总结
我对自己的要求是,对于 public 头文件中的所有信息,都应该进行详细的注释,方便使用者查看。而在代码源文件中可以不详细注释,自己可以理解。但是也需要按照Doxygen的格式列出基本信息方便回顾代码的时候提醒自己,让自己了解自己当时在想些什么,为什么要这么做。
对于一个开发团队,尤其是大公司,都会有严格规定的标准,包括代码风格,各种git hook,还有类似Doxygen这种文档工具。有些工程师会觉得这些“标准”很繁琐,很难要求自己遵守。但是不可否认的是,各种代码标准的目的不是以折磨程序员为乐趣,而是为了提高程序员的生产力,提高代码的可读性,可维护性,可靠性。
但是有时候,为了追求标准化而去不断强调“标准”这个概念,甚至花费大量的时间精力去专注在“标准”们上也是很荒唐的。所以无论我们使用哪些“标准”,参考各大开发团队的标准,形成一套适合自己团队的开发规范即可,内容永远大于形式。
这不是一篇Doxygen的使用教学,而是想推荐类似Doxygen这种代码文档注释管理工具,对于如何使用Doxygen,强烈建议参考官方教程:
Doxygen Manual: Overviewwww.doxygen.nl
因为Doxygen对我和我们团队的开发提供了很大的帮助,因此推荐,祝开发愉快:D