Code Style

新版代码格式标准 (2018-12-7)

  • GNAQ 的 OI 代码风格改进自旧版风格以及 Rust 式代码风格。

预编译指令

顺序:

  • pragma
  • include
  • define
  • undef

缩进

define undef 继承上层缩进,其余不缩进。

T = 4S

写法

include 中全部使用 <> 而非 "" ;

include 中不使用空格。

define undef 中允许被定义的宏全部大写全部小写,其余情况不允许使用大写。

限制

不使用 #if #else #elif #endif #ifdef #ifndef #endif #line #error 以及其他预编译命令。

命名空间

写法

  • 总是使用 using namespace std  导入

using std::cin using std::cout using std::endl using std::min using std::max

在代码出现过的 std namespace 中的函数。

  • 命名空间中可以使用 #define ,但必须在结尾处 #undef

#define 指令应置于命名空间的开头处。

  • 任何大型数据结构使用其大写简写为名称的单独 namespace , 如

namespace KDT namespace SGT namespace TRP

并总是在命名空间的结尾处 } 后缀一分号 ; ,例如:

顺序

应置于代码开头处的所有预编译指令之后。

缩进

继承上层缩进,T = 4S 。

花括号

写法

  • 使用 Allman 式花括号,也即花括号换行。 例如:

  • 在任何代码片段中不使用任何 , 运算符连接两个语句,其正确格式为:

for (;;) { Func1(); Func2(); } 也即一对花括号的每一个前后都有一个空格,语句之间也有一个空格

写法

  • 每行可以有多个语句,但必须使用一个空格隔开。
  • 多个意义独立的代码块之间应用一个空行隔开 ;
  • 非空行尾不应有多余的空格 ;
  • using namespace std; 后有一空行 ;
  • 函数、成员函数、结构体、全局变量块之间必须用空行隔开。
  • if for while 等语句,若其后只有一条语句 (或嵌套) ,可以直接缩进 (T = 4S) 而无需 {} 。

缩进

继承上层缩进 , T = 4S 。

小括号

写法

声明及调用函数时的括号紧跟其他字符外,任何成对小括号的前后必须有一个空格隔开其他字符,如:

for (;;) Func1();

if (case1) { .. }

int i = (j * 100 + log2(100) );

( 若 ) 后接的是 ; 则空格可以省略 )

指针与引用

写法

  • OI 代码中不使用指针。
  • 引用部分采用 Rust 式命名,任何引用前的标识符 & 和引用变量之间用一个空格隔开,若前有类型标识符,则引用标识符紧跟类型标识符,如

缩进

继承上层缩进 , T = 4S 。

函数

写法

  • 函数采用大驼峰命名法,选择性地加入 _ ,如:

void Update()  int Qry() Mat Gauss_Elimination()

  • 空函数体必须为以下格式:

void Func1() {}

缩进

继承上层缩进 , T = 4S 。

空格

写法

  • 逗号后必须有一空格。前面不能有空格。
  • 冒号的两侧必须有一空格。
  • 双目、三目运算符两侧必须有一空格。
  • ++ -- 前/后不需空格。
  • 若非 C++1x ,则形如 vector< pair<int, int> > 的声明,每对 <> 前后空格需要对称。
  • :: . 的两侧不应有空格。
  • 初始化列表前后不需空格,如 max({a, b, c});

缩进

继承上层缩进 , T=4S 。

注释

缩进

继承上层缩进 , T=4S 。

写法

单行注释使用 // ,之后应有一空格,如 // do something 。

多行注释使用 /**/ ,其中 /* 和 */ 应独占一行,且 /* 和 */ 后应有一空行,例如:

 

reStructuredText 一个轻量级的标记语言

首先你要

然后在菜单栏里选择reStructuredText模式,Ctrl+L打开实时预览。

 

偶然发现了这个神奇的语法自由的文本标记语言。

这里有示例文档(pdf) 配合代码食用。

 

一点黑科技

一个很骚的写法(如果你也懒)

这样声明的”,\n”实质是一个临时的字符数组(后面是指针[]),而这个字符数组并不需要每次print都声明一次,(解释来自知乎)原因是可以把”,\n”看成一个指针 编译器在编译的时候会把这样的字符串保存到静态区,在程序里每一次使用这个字符串时都会指向那个区域,所以不用担心太大常数。


以下等式皆成立:

因为C语言的底层都是指针,数组的实现也是。对于compiler来说,它们没有区别:


lambda表达式

(SDOI2018正式兹瓷了C++11,所以这让C++11的诸多特性得以发挥功效)

见百度百科?

提高调试效率-GNAQ的变量命名规则

GNAQ的变量命名规则分如下部分:

(函数名同样适用)

1.固定且有奇怪含义的变量(尽量不要理会)

at 邻接表存边时的表尾指针

ed (edge_struct) 邻接表结构体的名字

l (LCA_array) 含有LCA算法时用作记录LCA

pointer 巨长的变量名,但在写的时候很少访问它,这是邻接表里每个点的链尾的位置(更常用的貌似是next,推荐使用next,但要按照规则2缩写为nextx)

opt (operation_type) 用作操作次数变量或操作类型变量被读入

2.前(后)缀式与全缩式命名规则 和 常见单词缩写 和 缩写方法

前(后)缀式命名规则

以hsize,wpoint和tstamp为例

hsize=heap_size 堆大小

wpoint=white_point Prim算法的白点

tstamp=time_stamp 时间戳

前缀式命名规则的适用范围是某种结构或某种算法的信息变量

例如结构的大小、算法的步数、树的子节点个数。

前缀式命名规则基于英文的全拼(通常是两个或三个单词)缩写第一个单词而全写第二个单词,当且仅当第二个单词较短 , 且第一个单词( 表明变量的从属关系 )的缩写较好辨认 (比如叶子序号 线段树大小 距离

上面的例子均按照此规则缩写。

更多例子: **size **dis (distance太长而使用简写) **pos (position太长而使用简写)

而缩写第二个单词全写第一个单词,当且仅当第一个单词较短而第二个单词的缩写较好辨认。

比如edgenum nodenum nodev (v=value)  ctr* (ctr=counter 计数器)  cache** (表明是某某的缓存变量)

·

全缩式命名规则

若变量名都不符合前缀式命名规则,使用全缩式命名。

如ansf=answer_flow 既不符合前缀式缩写,(ans缩写为大多数人固定搭配,缩写为a则加深了理解难度),也当然不符合后缀式缩写(一个题外话:flow_ans是符合的,但是当时我不知道为啥脑子抽了就是写了个ans_flow)

那就全部缩写。缩写后意义较明显的单词只取首字母,而意义较不明显的单词取部分缩写。

·

缩写方法

  1. 原则是用最少的字母缩写,看到后在众多相似单词中能快速还原到正确的一个。
  2. 单词中发元音的字母尽量加入到缩写,而发辅音的较少添加
  3. 如果这样你还不知道怎么缩写,那就取前三个字母
  4. 缩写主要是给你看的,如果你扫了脑子一圈还没想到有别的常用意义可以如此缩写,那这个缩写就是好用的。你当然也可以使用其他易懂的缩写格式

比如:flow=fo/fl/fw

fo中o也发元音好像比较合适,但fo也可以是for的缩写或者former的缩写,容易产生混淆,尽量避免使用这种缩写(常用含义较多的)。

fl好像比较合适

fw可以是forward的缩写(且w在原词不发音,不应用这个单词缩写)

3.全拼式命名规则

如mapx,edgex,dis

如果变量名原本是一个单词,比较长而有缩写形式,使用缩写。没有就造一个。

如果较短(≤5个字符),使用全拼并在末尾+x

这样做的好处是防止卡关键字(试试prev!!你会被吓到的)

有时候使用缩写后也可以+x,也是为了防卡关键字

4.其他

尽量不要使用单个字母的变量,最佳范围2~5 (6)个字母之间

函数名可以使用下划线,变量名尽量不使用下划线,更好区分。

成员变量应该是一个名词或者偏正短语

函数应该是一个动词或者动宾短语

 

最重要的是有一套自己的常用变量缩写与变量名常用单词

当你写猪国杀 杀蚂蚁 立体图以及其他超过200行的程序,调试效率会非常高,因为在如此多的变量之下不会忘记每一个的含义,这才是最主要的。

这样当你打开屯了一个月的代码,你会用最快的时间进入状态,不需要纠结在变量名

当你请他人帮忙的时候,发代码他也能快速读懂