Doxygen - 治好了我的代码注释强迫症

在编写大量代码时,或者与多人协作进行开发时,文字记录很重要(文档或注释),尤其对于开发者本人回顾之前写过的代码和 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://qizongwu.com/posts/coding-style)中,我介绍了使用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  *//** @addtogroup DOXYGEN_API * @brief Doxygen api example. * * Detailed api description. * * @{ */#ifndef _TEMP_DOXYGEN_H#define _TEMP_DOXYGEN_H#ifdef __cplusplusextern "C" {#endif/* INCLUDE FILES */#include //#include //#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 this 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 @. * We can also include text verbatim, * when the language is not the one used in the current source file (but * be careful as this may be supported only by recent versions * of Doxygen). By the way, this is how you write bold text 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  * @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 ) * 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 this 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 @. * We can also include text verbatim, * when the language is not the one used in the current source file (but * be careful as this may be supported only by recent versions * of Doxygen). By the way, this is how you write bold text 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  * @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