注释
注释是代码中的说明文字,编译器完全忽略它们。良好的注释解释"为什么"而非"做什么"——代码本身应该足够清晰地表达"做什么"。C99 支持两种注释形式,其中 // 单行注释是 C99 新增的特性。
块注释 /* ... */
块注释以 /* 开始,以 */ 结束,可以跨越多行:
/* 这是单行块注释 */
/*
* 这是多行块注释。
* 每行开头的星号只是为了美观,不是语法要求。
* 块注释常用于文件头、函数说明等较长的说明。
*/
int sum(int a, int b)
{
/* 计算两数之和 */
return a + b;
}
块注释不能嵌套:
/* 外层注释开始
/* 试图嵌套注释 */ /* 错误!这里的 */ 结束了外层注释
这行代码不再被注释,会导致语法错误
*/
某些编译器支持嵌套块注释作为扩展,但标准 C 不允许。如果需要临时注释掉包含块注释的代码段,使用 #if 0 条件编译更安全:
#if 0
/* 这段代码被临时禁用 */
int old_function(void)
{
/* 内部还有注释 */
return 0;
}
#endif
单行注释 // ...
C99 引入了 // 单行注释,从 // 到行尾的所有内容都被视为注释:
int x = 10; // 初始化计数器
// 以下代码计算阶乘
int factorial(int n)
{
if (n <= 1) return 1; // 基线条件
return n * factorial(n - 1); // 递归调用
}
单行注释特别适合简短的行尾说明。如果注释内容较长,仍然建议使用块注释:
// 不推荐:单行注释太长,换行后不再是注释
// 这个函数实现了快速排序算法,它选择第一个元素作为枢轴,
// 然后将数组分为两部分,左边小于枢轴,右边大于枢轴,
// 最后递归排序两部分。
/* 推荐:多行说明用块注释 */
/*
* 快速排序实现。
* 选择首元素为枢轴,分区后递归排序。
*/
注释的最佳实践
注释应解释意图,而非重复代码:
/* 差:重复代码 */
i = i + 1; /* i 加 1 */
/* 好:解释为什么 */
i = i + 1; /* 跳过哨兵元素 */
用注释标记待办事项:
/* TODO: 处理 n = 0 的边界情况 */
/* FIXME: 当前实现 O(n^2),需要优化 */
/* NOTE: 这个算法假设输入已排序 */
/* HACK: 临时方案,后续重构 */
文件头注释:
/*
* file: math_utils.c
* brief: 数学工具函数集合
* author: Alice
* date: 2024-01-15
* version: 1.0
*/
函数注释:
/*
* brief: 计算两个整数的最大公约数
* param a: 第一个整数,必须为正
* param b: 第二个整数,必须为正
* return: a 和 b 的最大公约数
* note: 使用欧几里得算法
*/
int gcd(int a, int b)
{
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
过度注释与注释不足
注释不是越多越好。自解释的代码优于大量注释:
/* 过度注释 */
/* 打开文件 */
FILE *fp = fopen("data.txt", "r");
/* 检查文件是否成功打开 */
if (fp == NULL) {
/* 打印错误信息 */
printf("Error\n");
/* 返回错误码 */
return -1;
}
/* 自解释的代码 */
FILE *input = fopen("data.txt", "r");
if (input == NULL) {
perror("Failed to open data.txt");
return EXIT_FAILURE;
}
关键原则:
- 复杂的算法需要注释解释思路
- 边界情况和特殊处理需要注释说明原因
- 显而易见的代码不需要注释
- 注释必须与代码同步更新,过时的注释比没有注释更危险