前言
上期,咱们写了一个 史上最强C语言屎山代码之Hello World炸裂版 让人看着就懵逼,你想过为什么看不懂吗?
因为:没有注释,代码没按规范写
这期,咱就来聊聊C/C++中写代码时的注释规范
由请咱们的Doxygen登场!
一、什么是Doxygen
Doxygen风格代码注释是一种标准化的注释格式,用于生成清晰、结构化的代码文档,广泛支持 C/C++ 等语言,且能被 Visual Studio 2022 等工具识别和解析。其核心特点是通过特定标签(以 @
或 \
开头)描述代码元素的功能、参数、返回值等信息,便于自动生成 HTML、PDF 等格式的文档,同时提升代码可读性。
二、Doxygen注释标签
1. 文档结构标签
标签 | 说明 |
---|---|
@file | 指定文件归属与描述 |
@brief | 简要描述(显示在摘要中) |
@details | 详细描述(可选) |
@author | 标注作者 |
@date | 标注日期 |
@version | 指定版本号 |
@copyright | 版权声明 |
@mainpage | 定义主页面内容 |
@page | 创建独立页面 |
@section | 定义章节 |
@ingroup | 将元素归入功能组 |
@defgroup | 创建功能组 |
2. 函数与方法标签
标签 | 说明 |
---|---|
@param [in] | 输入参数说明 |
@param [out] | 输出参数说明 |
@return | 返回值说明 |
@retval | 特定返回值说明(多个值) |
@throws | 异常说明(C++) |
@pre | 前置条件 |
@post | 后置条件 |
@warning | 警告信息 |
@note | 补充说明 |
@deprecated | 标记为弃用 |
3. 类与结构体标签
标签 | 说明 |
---|---|
@class | 类说明 |
@struct | 结构体说明 |
@enum | 枚举说明 |
@extends | 继承关系说明 |
@implements | 实现接口说明 |
@interface | 标记为接口 |
@final | 标记为不可继承 |
@threadsafe | 线程安全说明 |
4. 模板与泛型标签
标签 | 说明 |
---|---|
@tparam | 模板参数说明 |
5. 格式化与特殊内容标签
标签 | 说明 |
---|---|
@code | 插入代码块 |
@example | 引用示例文件 |
@image | 插入图片 |
@dot | 插入 DOT 图形(流程图) |
@formula | 插入数学公式 |
@note | 创建注意事项框 |
@warning | 创建警告框 |
6. 交叉引用标签
标签 | 说明 |
---|---|
@see | 参见其他元素 |
@sa | 同上(更简洁) |
@ref | 创建内部链接 |
@link | 带文本的链接 |
7. 语言特定标签
标签 | 说明 |
---|---|
@namespace | 命名空间说明(C++) |
@var | 变量 / 全局变量说明 |
@typedef | 类型定义说明 |
8. 其他杂项标签
标签 | 说明 |
---|---|
@todo | 待办事项 |
@bug | 已知问题 |
@cond | 条件编译控制 |
@if | 条件判断 |
@image | 插入图片 |
@test | 测试用例说明 |
使用提示
- 标签前缀:可使用
@
或\
(如@param
与\param
等价)。 - 多行注释:使用
/** ... */
包裹。 - 单行注释:使用
///
或//!
。 - 右侧注释:使用
///<
或//!<
(如变量注释)。
三、如何使用Doxygen代码注释
1. 文件头部注释
必选内容:版权声明、文件功能、命名空间、依赖关系。
/**
* @file: network/tcp_client.h
* @brief: TCP客户端实现,基于Boost.Asio
* @namespace: net::tcp
* @copyright: Copyright (c) 2023 CompanyName
* @note: 依赖 boost/asio.hpp 和 error/error_code.h
*
* @authors: 王五(架构)、赵六(实现)
* @date: 2023-05-20
* @version: 3.0
*/
2. 类注释
必选要素:设计意图、生命周期管理、线程安全性、使用模式。
示例:
/**
* 线程安全的TCP客户端
*
* @note 采用RAII模式管理连接,析构时自动关闭
* @warning 非拷贝构造,不可复制
*
* 使用示例:
* try {
* TcpClient client("127.0.0.1", 8080);
* client.connect();
* client.send("Hello");
* } catch (const std::exception& e) {
* // 处理异常
* }
*/
class TcpClient final : public NetworkClient {
public:
TcpClient(const std::string& host, uint16_t port);
~TcpClient() override;
// 禁用拷贝构造和赋值
TcpClient(const TcpClient&) = delete;
TcpClient& operator=(const TcpClient&) = delete;
// ...
};
3. 函数 / 方法注释
必选要素:功能描述、参数约束、返回值语义、异常规格、前置 / 后置条件。
示例:
/**
* 异步发送数据
*
* @param [in] data 待发送的数据缓冲区,不可为空
* @param [in] size 数据大小(字节)
* @param [in] callback 完成回调函数,可空
*
* @pre 已调用connect()且连接成功
* @post 数据将加入发送队列,由IO线程处理
* @throws NetworkException 若连接已断开
*
* @example
* client.async_send(buffer, size, [](bool success) {
* if (success) cout << "发送成功";
* });
*/
void async_send(const char* data, size_t size,
std::function<void(bool success)> callback = nullptr);
4. 模板注释
重点说明:类型参数约束、特化场景、性能特性。
示例:
/**
* 固定大小的线程安全对象池
*
* @tparam T 对象类型,必须有默认构造函数
* @tparam Alloc 分配器类型,默认std::allocator
*
* @note 预分配N个对象,避免运行时动态分配
* @warning T类型析构函数不应抛出异常
*/
template <typename T, typename Alloc = std::allocator<T>>
class ObjectPool final {
public:
explicit ObjectPool(size_t capacity);
// ...
};
5. 行级注释
重点标注:
- RAII 资源管理(如智能指针、锁)。
- 模板元编程和复杂类型推导。
- STL 算法和自定义比较器。
// 使用RAII锁保护共享资源
{
std::lock_guard<std::mutex> lock(mutex_); // 自动释放锁
data_.push_back(std::move(item));
}
// 模板元编程:计算编译时常量
template <int N>
struct Factorial {
static constexpr int value = N * Factorial<N-1>::value; // 递归展开
};
template <>
struct Factorial<0> { static constexpr int value = 1; }; // 特化终止条件
// 使用自定义比较器的优先队列
auto cmp = [](const Task& a, const Task& b) { return a.priority() < b.priority(); };
std::priority_queue<Task, std::vector<Task>, decltype(cmp)> task_queue(cmp);
6. 特殊场景注释
6.1 Lambda 表达式
// 捕获this的lambda:注意生命周期管理
auto worker = [this]() {
while (running_) {
process_task();
}
};
// 移动捕获unique_ptr
auto task = std::make_unique<Task>();
queue_.push([task = std::move(task)]() {
task->execute();
});
6.2 异常安全
/**
* 强异常安全的交换函数
* @throws 无(不抛出异常)
*/
void swap(MyClass& other) noexcept {
using std::swap;
swap(data_, other.data_); // 调用ADL查找最佳swap实现
}
6.3 性能关键代码
// 使用emplace_back避免临时对象拷贝
for (const auto& item : source) {
target.emplace_back(std::move(item)); // 直接构造对象
}
// 性能优化:展开循环减少分支预测错误
for (int i = 0; i < 4; ++i) { // 假设已知数组大小为4
result[i] = data[i] * scale;
}
7. 注释风格约定
- Doxygen 风格(推荐):
/** * 多行注释 * @param ... */
- 单行注释:
// 简短说明
。 - 文件包含顺序:
// 本模块头文件 #include "my_class.h" // 系统头文件 #include <iostream> // 第三方库头文件 #include <boost/asio.hpp> // 项目内其他模块头文件 #include "utils/log.h"
8. 注释禁忌
- 重复 obvious 代码:
// 将x加1 ++x; // 错误!
- 忽略重要细节:
// 处理请求 void process_request(Request& req); // 错误!未说明线程安全和异常情况
- 使用模糊术语:
// 修复了一个问题 // 错误!应说明具体问题(如:修复了大数据量下的内存泄漏)
9. C++ 特殊注意事项
- 智能指针:标注所有权语义(如
@param [in] ptr 转移所有权的unique_ptr
)。 - 线程安全:明确标注函数是否线程安全(如
@threadsafe
或@not_threadsafe
)。 - 模板特化:说明特化场景(如
@note 针对std::string的特化版本优化了内存分配
)。 - 移动语义:标注参数是否会被移动(如
@param [in,out] data 内容将被移动
)。
工具链支持
- 文档生成:Doxygen、Sphinx(结合 Breathe)。
- 静态分析:Clang-Tidy(检查注释与代码一致性)、CppCheck。
- 格式化:clang-format(统一注释格式)。