蒟蒻 AstralNahida 的码风

前言

这里是蒟蒻 OIer AstralNahida 在 OI 中的码风的详细介绍。

个人认为码风相当清晰,供给各位参考。

约定

对于一些表示必要性的关键词,从 mustmustn't 排序如下:

必须 > 尽量 > 应当 > 建议 > 可以 > 不建议 > 不应当 > 尽量不 > 不得。

为方便阅读,本文中所有上述关键词都用粗体字表示。

另外,若没有**「至少」、「至多」** 等词的限定,所有的数字默认为严格的

例如「中间有一个空行」中的「有一个」默认为**「有且仅有一个」**。

第一部 · 整体

这里贴一份本人做洛谷 P2078 的代码:

cpp 复制代码
#include <iostream>
#include <map>

#define upFor(i, a, b) for (int i = a; i <= b; i++)

#define Nahida return 0

std::map<int, int> pa;

int findRt(int x) {
    return x == pa[x] ? x : pa[x] = findRt(pa[x]);
}
void merge(int x, int y) {
    pa[findRt(x)] = findRt(y);
}
bool haveSameRt(int x, int y) {
    return findRt(x) == findRt(y);
}

int main(void) {
    int aVtxNum, bVtxNum, aEdNum, bEdNum;
	std::cin >> aVtxNum >> bVtxNum >> aEdNum >> bEdNum;
	upFor (i, -bVtxNum, aVtxNum) pa[i] = i;
	upFor (i, 1, aEdNum + bEdNum) {
		int u, v;
		std::cin >> u >> v;
		merge(u, v);
	}

	int ansA = 0, ansB = 0;
    upFor (i, 1, aVtxNum)
		if (haveSameRt(pa[i], 1)) ansA++;
	upFor (i, -bVtxNum, -1)
		if (haveSameRt(pa[i], -1)) ansB++;

	std::cout << std::min(ansA, ansB) << '\n';

	Nahida;
}

大概是这样式的。

由此可以看出,我的代码大致分为四个部分:

  1. #include 部分,用于包含代码所需的头文件;
  2. #define 部分,用于进行一些简化代码的宏定义以及自己的一些小癖好(如 Line 6 的 #define Nahida return 0);
  3. 全局变量、常量及函数的声明及定义部分;
  4. 主函数部分。

这一部只是提供代码的整体观感而已,码风具体规则详见下文。

第二部 · 头文件包含及宏定义

第一章 · 头文件

对于任意项目,在写代码的时候不得 使用万能头 <bits/stdc++.h>。除了刷题的时候可以少点时间,其它全是缺点。

对于引用的头文件,C 标准的头文件应当 使用以 c 为前缀的形式,而非 .h 为后缀的形式。

例如,<string.h> 应当 写成 <cstring>

对于所有头文件,建议 将 C 标准的头文件放在一起,后必须 接一个空行再把 C++ 的头文件包含进来。

另外,也建议 以头文件的作用将包含的头文件分类,每个类别中间必须 由一个空行分割。

上述两种分段方式任选其一即可。

另外,不得 使用 using namespace std;,否则函数名、变量名容易出现冲突。

必要时,可以 使用 using std::sort; 此类方法,但仍需要确定函数名、变量名不出现冲突。


第二章 · 宏定义

对于任意宏定义,其作用为下列两种的任意一种:1° 简化代码或定义常量;2° 满足自己的小癖好。

如果一份代码中同时出现了这两种宏定义,则需要把两种宏定义分别放在一起,中间必须由一个空行分隔。

第三部 · 缩进及大括号

第一章 · 缩进

缩进必须 使用 2 空格缩进或者 4 空格缩进,但不得 混用。

在每一个大括号的内部或者 casepublicprivate 等的内部,必须 使用一份缩进。

对于很长的表达式,需要分行来确保可读性、可维护性时,也必须 使用一份缩进。

任意 # 开头的指令之前不得使用缩进,无论它是否在原本需要使用缩进的块内。


第二章 · 大括号

大括号的常用风格有以下两种:

  • 「通透」风格:
cpp 复制代码
if (1 + 1 == 2)
{
    break;
}
  • 「饱满」风格:
cpp 复制代码
if (1 + 1 == 2) {
    break;
}

必须 使用这两种中的任意一种,且不得 混用。

这里更建议使用第二种,否则若内部的语句很少,整个代码观感就比较空虚。

第四部 · 空格及空行

第一章 · 空格

必须妥善利用空格,否则代码过于紧凑(说难听点,挤成一坨),影响观感和可读性、可维护性。

以下列出的位置必须使用一个空格:

  • 双目运算符的左右两侧(特殊地,+- 作为正负号时,与后接的表达式之间不得使用空格);
  • 流运算符的左右两侧;
  • if 系列、whiledo-whileswitchforforeach 等与后接的(或前导的)大括号或小括号之间;
  • 一对大括号在同一行时,左大括号的后面和右大括号的前面;
  • 三目运算符中,?: 的左右两侧;
  • * 表示指针类型时,若后接变量名,与变量名之间;
  • #include 与后接的 <> 之间;
  • 使用「饱满」风格的大括号时,左大括号与前导内容之间;
  • ,; 与后接的表达式之间;
  • 其它必须使用空格的地方。

任何除了作为缩进以外的 地方,都不得出现几个空格连用的情况。

以下列出的位置不得使用空格:

  • ::->. 的左右两侧;
  • * 表示指针所引用的内容时,与后接变量名之间;
  • * 表示指针类型时,与前导的类型名之间;
  • 函数名与后接小括号之间;
  • ,; 的左侧;
  • 单目运算符与参与运算的表达式之间;
  • +- 作为正负号时,与后接的表达式之间;
  • 其它不得使用空格的地方。

第二章 · 空行

必须妥善利用空行,否则代码过于紧凑(说难听点,挤成一坨),影响观感和可读性、可维护性。

在第一部中提到,代码大致分成四个部分,其中每个部分之间必须 使用一个空行。

在其它的任何位置,应当根据代码内容合理地使用一个空行进行分隔,确保代码可读性、可维护性。

第五部 · 变量、常量及函数

第一章 · 定义

若非必要,尽量不 定义全局变量。

定义常量,必须 使用 #defineconst 中的任意一种,不得 混用。

定义函数时,若函数体不长,建议 在主函数之前声明并定义;若函数体很长,应当在主函数之前声明,在主函数之后定义。


第二章 · 命名

命名尽量不 过长,否则使用没有自动补全的编辑器时容易累死,表达式也容易过长,影响观感和可读性、可维护性。

同时,命名不得 使用过于简单、没有意义的名字,尽量 在命名中体现出该函数的作用。题目所给出的变量名除外。

需要注意的是,过于简单、没有意义 的核心是没有意义,若单个字母有明显意义的,不算作不规范命名,如 for 中的 i、表示顶点的 uv 等。

当然,变量较多时,确实不建议使用单个字母命名。

后记

差不多就是这样了。我这里给出的码风规范其实是相对宽松的,有很多自由的空间。

若有需要补充的地方,欢迎大家指出!

有些小萌新可能会问,码风真的有这么重要吗?

当然有的。上面我也提到了不少次,养成好的码风究其根本是为了保证代码的可读性和可维护性,同时保证代码美观。

好的码风对于 OIer 来说无疑是极其重要的,正所谓「码如其人」,如果你是一个有追求的 OIer,那么你应当拥有一个整洁、统一的码风。

当然,如果你决定将来做程序设计工作,你也应当养成好的码风,否则项目迟早被写成屎山。

好啦,就到这里吧,祝各位热爱自己的 OI 生涯。

更新记录

  • 2025/4/26 14:09 本文正式告成,发布。