我给自己列了一份C++编码规范

老师让我们上网了解编码规范,写一份本学期打算遵守的规范。刚看到这个题目的时候我有点困惑——算法课不是应该刷题吗?编码规范这种东西,能帮我多过几个测试点吗?但翻了几篇Google的文档,又回头看了看自己上学期写的数据结构代码,我改变想法了。因为我发现,有些代码我现在已经看不懂了。
一、先说说我为什么开始在意这个
上学期写链表的时候,我写过这样一段:
cpp
int find(Node* h, int x) {
Node* p = h;
while (p) {
if (p->v == x)
return p->i;
p = p->n;
}
return -1;
}
逻辑没问题。但几个月后我再看到这段代码,盯着 p->v 和 p->i 愣了十几秒——哦,v 是 value,i 是 index,n 是 next。当时写的时候觉得“这还用解释?”,现在看的时候只想回到过去给自己两巴掌。这种坑踩过一次就忘不了,所以这学期我打算认真对待编码规范。不是为了写得好看,而是为了少出 bug,也为了三个月后的自己还能看懂现在写的代码。
我主要参考了这几份资料:Google C++ Style Guide、C++ Core Guidelines,还有 PEP 8。PEP 8 虽然是 Python 的,但它关于缩进和命名一致性的思想是通用的。Google 的规范很工程化,有些条款对算法题来说太重了,比如头文件顺序、include guard、禁止 using namespace std,我暂时不打算全盘照搬。但命名、排版、注释这几块,我觉得可以直接借鉴。
下面是我这学期打算用的规范。
二、命名:让名字自己解释自己
我以前很喜欢写 a、b、tmp、flag。代码刚写完的时候当然知道它们是什么意思,但问题是,这种信息只存在于我写代码那一刻的记忆里,并没有真正存在于代码中。
所以我的第一条规则是:能通过名字表达的信息,就不要依赖注释和记忆。
普通变量用蛇形命名法,也就是小写字母加下划线:
cpp
int student_count;int max_capacity;int target_value;
布尔变量用 is_ 或 has_ 开头:
cpp
bool is_valid;bool has_answer;
函数名用动词开头,小写加下划线,让人一眼看出它要做什么:
cpp
int binary_search_index();void read_input();void print_answer();
类和结构体用大驼峰:
cpp
class DisjointSetUnion;struct TreeNode;
常量我决定用全大写加下划线,和宏类似:
cpp
const int MAX_N = 1000;const int INF = 0x3f3f3f3f;
但算法题里有些短名称是约定俗成的,强行改成长名字反而增加认知负担。比如:
cpp
for (int i = 0; i < n; i++) { ... }int n, m; // 点数和边数vector dist; // 最短距离int dp[MAX_N]; // 动态规划数组
这些在算法教材里就是这么写的,保留它们没问题。我的判断标准是:如果这个名字在算法领域的标准教材里就是这么用的,那就保留;如果只是我自己为了偷懒随便起的,那就老老实实写全。
文件命名也尽量体现算法内容,比如 merge_sort.cpp、dijkstra.cpp、knapsack.cpp,而不是 test1.cpp、new.cpp、final_final.cpp。
三、排版:整齐不是为了好看,是为了少犯错
我以前写代码喜欢把逻辑挤在一起:
cpp
if(a>b){c=a;a=b;b=c;}for(int i=0;i<n;i++){if(arr[i]>0)sum+=arr[i];}
这种代码能跑,但调试的时候很痛苦。后来我改成多行写法,虽然多敲了几个回车,但读起来舒服多了。
我打算遵循这些排版规则:
统一用 4 个空格缩进,不用 Tab。 Google 用的是 2 空格,但那是 Google 的选择。我选 4 空格,因为层级看起来更明显。
大括号不单独换行,跟在语句后面。而且就算代码块只有一行,也加大括号:
cpp
if (n == 0) { return 0;}
不加大括号的写法在代码短的时候看起来挺清爽,但一旦以后要往里面加一行,忘了加括号就是一个很难发现的逻辑错误。
运算符两侧加空格,逗号后面加空格,函数名和左括号之间不加空格。
cpp
int sum = a + b;for (int i = 0; i < n; i++) { process(i, j);}
不同逻辑块之间用空行分隔。 输入、核心逻辑、输出各空一行。代码长起来之后,空行就是视觉上的路标。
行宽尽量控制在 80 到 100 个字符以内。 太长的表达式换行写。
我还会用 clang-format 来格式化代码。在 VS Code 里保存时自动格式化,这样就不用每次手动调空格了。我写了一个 .clang-format 文件,基于 Google 风格,但把缩进改成 4 空格。
四、注释:解释为什么,而不是重复做什么
以前我写注释是这样的:
cpp
i++; // i加1sum += arr[i]; // sum加上arr[i]
这种注释没有任何信息量。代码本身已经说得很清楚了,注释再说一遍等于浪费时间。
好的注释应该解释“为什么这样做”,而不是“做了什么”。
比如二分查找里:
cpp
// 用 mid = left + (right - left) / 2 而不是 (left + right) / 2// 是为了避免 left 和 right 都很大时相加溢出int mid = left + (right - left) / 2;
再比如动态规划:
cpp
// 当前状态只能由上一个合法状态转移而来// 所以这里不需要考虑不合法的情况dp[i] = max(dp[i - 1], dp[i - 2] + a[i]);
函数上方我打算写一个简短的注释,说明功能、参数和返回值。文件开头也会写算法名称、主要功能、时间复杂度和空间复杂度。这样复习的时候能快速了解程序内容。
注释语言我用中文。代码用英文命名,注释用中文解释,这样既能保持代码的国际化习惯,又能让注释真正起到帮助理解的作用。
五、变量和类型:C++ 的坑比算法还多
C++ 有很多问题编译器不会帮你抓,得靠自己小心。
变量一定要初始化。 这个坑我踩过,前面已经说了。现在我会在声明的时候就给初始值:
cpp
int sum = 0;
int max_value = -INF;
Node* root = nullptr;
合理使用 const。
不需要修改的数据就加 const:
cpp
const int MAX_N = 1000;
void print_array(const vector& numbers) {
for (int value : numbers) {
cout << value << " ";
}
}
函数参数用 const 引用,既避免复制,也防止函数意外修改原始数据。
注意整数溢出。 如果两个整数相加或者相乘的结果可能超过 int 的范围,就用 long long:
cpp
long long sum = 0;
long long result = 1LL * a * b;
我不会用 #define int long long 这种写法。虽然竞赛圈有人用,但那是坏习惯,容易出问题。我老老实实写 long long。
尽量缩小变量的作用域。 循环变量就在 for 里面声明,不要提前声明成全局变量。
范围 for 循环用 const 引用。 比如:
cpp
for (const auto& value : numbers) { cout << value << " ";}
这样不会复制元素,效率更高。
数组下标注意边界。 数组长度是 n,有效下标是 0 到 n-1。写循环的时候,i < n 和 i <= n 差一个字符,后果完全不同。
六、函数设计:main 不是垃圾桶
我以前喜欢把所有代码都塞在 main 里,结果 main 函数又长又乱,出了问题很难定位。
这学期我打算让 main 只负责组织程序流程:读入、调用核心函数、输出。核心算法放在单独的函数里,方便单独测试。
函数应该尽量只完成一项主要任务。比如排序算法可以拆成:
cpp
void read_array();
void merge_sort(vector& a, int left, int right);
void print_array(const vector& a);
函数参数尽量通过参数传递,不要过度依赖全局变量。如果函数只需要读取容器内容,就用 const 引用。
函数返回值要明确。如果函数需要返回计算结果,就选择合适的返回类型;如果只负责输出,就用 void。不要忘记必要的 return 语句。
七、算法实现:先想清楚再写
因为这是算法课,除了普通编码规范,我还想特别强调算法实现中的规范性。
写之前先明确输入输出。 题目要求处理哪些数据,最终输出什么,先想清楚再动手。
明确算法的适用条件。 二分查找要求数据有序,Dijkstra 要求边权非负,动态规划要求能建立合适的状态转移。写之前先检查输入是否满足条件。
注意循环边界。
这是算法题最容易出错的地方之一。比如二分查找,我打算统一用左闭右开区间 [left, right),循环条件是 left < right,这样不容易搞混。
避免死循环。
循环变量或循环条件必须能向终止状态推进。比如二分查找里,left = mid + 1 或者 right = mid,每次都要缩小查找区间。
分析复杂度。
每完成一个算法,我都会在文件头写上时间复杂度和空间复杂度。以前不写,后来发现复习时忘了这个算法是 O(nlogn) 还是 O(n²),写下来省事。
尽量按需 include 头文件。 bits/stdc++.h 虽然方便,但不是标准 C++ 头文件。我打算尽量写清楚:
cpp

include #include #include

这样也能提醒自己用了哪些库。
八、测试与调试:别让编译器骗你
编译通过不代表程序正确。我打算养成主动测试的习惯。
编译时开启警告:
bash
g++ -std=c++17 -Wall -Wextra -Wshadow -O2 main.cpp -o main
-Wall 和 -Wextra 能发现很多潜在问题,-Wshadow 能提醒变量遮蔽。我有一次在循环里写 int i,外面还有一个 i,就是被 -Wshadow 警告出来的。
测试要覆盖这些情况:
普通情况
边界情况:数组只有一个元素、目标值在第一个、目标值在最后一个、目标值不存在、数据有重复、输入达到最大规模
特殊情况:空输入(如果题目允许)、负数、溢出边界
尝试对拍。
这学期我想试试写一个暴力程序,随机生成数据,比较两个程序的输出。虽然有点麻烦,但对查找边界错误很有用。
提交前删除调试输出。
调试时输出的 cout << "mid = " << mid << endl; 一定要删掉,不然会影响评测结果。
我的提交前检查清单:
1.变量名能不能看出含义?
2.有没有未初始化的变量?
3.数组下标有没有越界?
4.二分中点会不会溢出?
5.调试输出删了吗?
6.文件头写复杂度了吗?
6.函数参数是不是 const 引用?
7.代码格式化了吗?
九、我的模板
把上面这些东西汇总起来,这学期我打算用这样的模板来写算法题。以二分查找为例:
cpp
/* * 算法名称:二分查找(左闭右开)

  • 功能:在升序数组 a 中查找第一个大于等于 target 的位置
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)
    */#include #include using namespace std;// 返回第一个大于等于 target 的下标// 如果不存在,返回 a.size()
    int lower_bound_index(const vector& a, int target) {
    int left = 0;
    int right = static_cast(a.size()); // 左闭右开:[left, right) while (left < right) { // 避免 (left + right) 溢出
    int mid = left + (right - left) / 2;
    if (a[mid] < target) {
    left = mid + 1;
    }
    else {
    right = mid;
    }
    }
    return left;
    }
    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector a(n);
    for (int i = 0; i < n; ++i) {
    cin >> a[i];
    }
    int target;
    cin >> target;
    int pos = lower_bound_index(a, target);
    cout << pos << '\n';
    return 0;
    }
    这个模板里体现了我打算遵守的规范:文件头说明算法信息,函数名和变量名能自解释,缩进和空格保持一致,关键逻辑加了注释,循环边界写清楚,特殊情况有处理,输入输出用了加速。
    十、这学期怎么执行
    我知道自己肯定不可能一次全做到。所以我不打算一口气吃成胖子,先从最重要的几条开始:
    命名不敷衍。 不再写 a、b、tmp、flag,除非是算法约定俗成的短名称。
    变量必须初始化。 声明的时候就给初始值。
    缩进和大括号统一。 用 clang-format 自动格式化。
    注释解释为什么。 不写废话注释。
    提交前检查边界和溢出。 尤其是二分、前缀和、动态规划这些容易出错的题。
    我还打算用 Git 管理代码。每道题一个 commit,commit message 写清楚做了什么,比如 solve: binary search。这样以后复习的时候能按算法分类找代码。
    另外,我会每周整理一次代码,把做过的题按算法分类放到 GitHub 仓库里。虽然现在代码写得还不够好,但至少要让它们能见人。
    参考资料
    Google C++ Style Guide. https://google.github.io/styleguide/cppguide.html
    C++ Core Guidelines. Bjarne Stroustrup & Herb Sutter. https://isocpp.github.io/CppCoreGuidelines/
    PEP 8 – Style Guide for Python Code. https://peps.python.org/pep-0008/
    我现在代码写得还不够规范,经常会出现缩进乱、命名随意、注释偷懒的问题。但我觉得,意识到问题就是改变的开始。这学期我想把这些规则慢慢养成习惯,让自己写出的代码不仅能跑,还要好读、好改、经得起别人 review。
    AC 是一次提交的终点,但代码的寿命比一次提交长得多。
posted @ 2026-10-01 11:56  与青山奏江河  阅读(4)  评论(0)    收藏  举报