1. 什么是 Doxygen?
Doxygen 是一个从源代码中提取注释并自动生成文档的工具。它支持 C++、C、Java、Python 等多种语言,可以输出 HTML、PDF、LaTeX、RTF、XML 等格式。你只需按照特定格式写注释,Doxygen 就能生成专业的 API 文档,类似 Qt、STL 那样的参考手册。
2. 为什么用 Doxygen?
-
代码即文档:注释和代码在一起,更容易同步更新。
-
自动化:无需手动编写独立的文档文件。
-
交叉引用:生成的文档可以点击跳转到类、函数、成员的定义。
-
图形化:支持生成类继承图、协作图、调用图等。
-
标准化:许多开源项目(如 KDE、Boost、OpenCV)都使用 Doxygen。
3. Doxygen 注释风格
Doxygen 支持多种注释风格,最常用的是 Javadoc 风格 (/** ... */)和 Qt 风格 (/*! ... */)。对于 C/C++,推荐使用 /** 开始的多行注释。
基本格式
cpp
/**
* @brief 简要描述(一句话概括)
* @details 详细描述(可选,可以写多行)
* @param 参数名 参数说明
* @return 返回值说明
* @note 注意项
* @warning 警告信息
*/
标记(
@brief、@param等)也可以使用\brief的形式(反斜杠),效果相同。
4. 常用标记(Tags)
| 标记 | 用途 | 示例 |
|---|---|---|
@brief |
简要描述 | @brief 初始化设备 |
@details |
详细描述 | @details 打开串口并配置波特率 |
@param |
函数参数说明 | @param port 端口号,如 "COM1" |
@return |
返回值说明 | @return 成功返回0,失败返回-1 |
@tparam |
模板参数说明 | @tparam T 数据类型 |
@note |
补充说明 | @note 调用前需要先打开设备 |
@warning |
警告信息 | @warning 非线程安全 |
@see |
参考其他文档 | @see close_device |
@code / @endcode |
插入代码块 | 展示用法示例 |
@deprecated |
标记为废弃 | @deprecated 请使用 new_func 代替 |
@todo |
待办事项 | @todo 增加错误处理 |
@bug |
已知缺陷 | @bug 高负载下可能丢包 |
5. 实际案例:数据采集软件的设备操作类
假设我们正在开发 sh 波形数据采集软件,其中有一个设备管理类。以下展示如何用 Doxygen 注释描述它。
头文件:device.h
cpp
#ifndef DEVICE_H
#define DEVICE_H
#include <cstdint>
#include <string>
#include <vector>
/**
* @brief 设备状态码
*/
enum class DeviceStatus {
OK = 0, ///< 正常
NOT_CONNECTED, ///< 未连接
TIMEOUT, ///< 通信超时
INVALID_PARAM ///< 参数无效
};
/**
* @class Device
* @brief 波形采集设备控制类
* @details 封装了与 USB/串口设备的通信、参数配置和数据读取功能。
* 内部使用 Boost.Asio 进行异步 I/O。
*/
class Device {
public:
/**
* @brief 构造函数
* @param port 设备端口号,例如 "COM3" 或 "/dev/ttyUSB0"
* @param baud_rate 波特率,默认 115200
*/
Device(const std::string& port, int baud_rate = 115200);
/**
* @brief 析构函数,自动关闭设备连接
*/
~Device();
/**
* @brief 连接设备
* @return DeviceStatus 连接结果
* @note 连接失败时可重试,重试间隔 500ms
*/
DeviceStatus connect();
/**
* @brief 断开设备连接
*/
void disconnect();
/**
* @brief 设置激励振幅
* @param amplitude 振幅,单位 V,范围 0~300
* @return true 设置成功;false 参数超出范围
* @see get_amplitude()
*/
bool set_amplitude(int amplitude);
/**
* @brief 获取当前振幅
* @return 当前振幅值(V),若未连接则返回 -1
*/
int get_amplitude() const;
/**
* @brief 触发一次测量
* @param num_points 采样点数,必须介于 100 到 10000 之间
* @return 包含测量数据的向量,空向量表示失败
* @note 该操作会阻塞直到测量完成或超时(5秒)
* @code
* Device dev("COM3");
* dev.connect();
* auto data = dev.trigger_measurement(2048);
* if (!data.empty()) {
* // 处理波形数据
* }
* @endcode
*/
std::vector<double> trigger_measurement(int num_points);
/**
* @brief 软件复位设备
* @return 是否成功发送复位命令
* @warning 复位后设备会丢失当前配置,需重新设置参数
*/
bool software_reset();
/**
* @brief 检查设备是否已连接
* @return true 已连接;false 未连接
*/
bool is_connected() const { return m_connected; }
private:
std::string m_port;
int m_baud_rate;
bool m_connected;
int m_amplitude; ///< 当前振幅,单位 V
/**
* @brief 发送命令并接收响应
* @param cmd 命令字节数组
* @return 响应字节数组,空表示超时或错误
*/
std::vector<uint8_t> send_command(const std::vector<uint8_t>& cmd);
};
#endif // DEVICE_H
实现文件:device.cpp(片段)
cpp
#include "device.h"
#include <iostream>
/**
* @file device.cpp
* @brief Device 类的实现
*/
// 构造函数实现
Device::Device(const std::string& port, int baud_rate)
: m_port(port)
, m_baud_rate(baud_rate)
, m_connected(false)
, m_amplitude(250) // 默认振幅 250V
{
// @todo 添加日志输出
}
// 触发测量的实现(简略)
std::vector<double> Device::trigger_measurement(int num_points)
{
if (!m_connected) {
// @bug 未连接时应该返回错误,而不是空向量
return {};
}
// 实际硬件通信...
return std::vector<double>(num_points, 0.0);
}
6. 如何生成文档?
步骤 1:安装 Doxygen
-
Windows :下载安装包 doxygen.nl
-
Linux :
sudo apt install doxygen graphviz(graphviz 用于生成图表) -
macOS :
brew install doxygen graphviz
步骤 2:生成配置文件
在项目根目录运行:
bash
doxygen -g Doxyfile
这会生成一个 Doxyfile 配置文件,你可以修改里面的选项。
步骤 3:修改关键配置(常用项)
ini
PROJECT_NAME = "波形采集软件"
PROJECT_BRIEF = "sh 波形数据采集工具"
OUTPUT_DIRECTORY = docs
INPUT = ./src ./include
FILE_PATTERNS = *.cpp *.h *.hpp
RECURSIVE = YES
EXTRACT_ALL = YES # 提取所有实体,即使没有注释
EXTRACT_PRIVATE = NO # 是否提取私有成员
GENERATE_LATEX = NO # 不需要 LaTeX 可关闭
GENERATE_HTML = YES
HAVE_DOT = YES # 需要安装 graphviz
UML_LOOK = YES
步骤 4:运行 Doxygen
bash
doxygen Doxyfile
生成的 HTML 文档位于 docs/html/index.html,双击即可在浏览器中查看。
7. 生成效果预览
打开 HTML 文档后,你会看到:
-
主页面显示项目名称和简介。
-
类列表(Class List)可点击
Device类。 -
类页面包含:
-
类的详细描述(
@brief+@details) -
成员函数列表,每个函数有参数、返回值、注意事项、代码示例。
-
成员变量列表。
-
继承图、协作图(如果开启
HAVE_DOT)。
-
8. 最佳实践建议
-
写注释就像在教别人用你的代码:假设使用者看不到源码,只读文档。
-
@brief必须写:让读者一眼知道这个函数/类做什么。 -
复杂逻辑用
@details展开:例如为什么采用某种算法、注意事项。 -
给示例代码 :
@code ... @endcode是最好的用法说明。 -
保持同步:修改代码时同步更新注释,否则文档就失效了。
-
不要过度注释 :明显的内容(如
set_amplitude设置振幅)不需要长篇大论,但参数范围、副作用、线程安全性要写清楚。
9. 常见问题
Q:Doxygen 能处理 Python 吗?
A:可以,但需要开启 OPTIMIZE_OUTPUT_JAVA 或使用 # 注释。不过 Python 社区更常用 Sphinx。
Q:如何忽略某些文件?
A:在 Doxyfile 中设置 EXCLUDE = path/to/ignore。
Q:中文注释会乱码吗?
A:确保源文件编码为 UTF-8,并在 Doxyfile 中设置 INPUT_ENCODING = UTF-8。
Q:生成的文档中函数参数类型没有链接?
A:确保 Doxygen 能找到类型定义的头文件(通过 INCLUDE_PATH 或 FULL_PATH_NAMES)。
10. 总结
Doxygen 是 C++ 项目文档自动化的工业标准。只需在头文件里按照规范写好注释,一条 doxygen 命令就能得到漂亮、可导航的 HTML 文档。对于团队协作或开源项目,这能大幅降低沟通成本。建议从今天开始,给你的所有公共接口都加上 Doxygen 注释。