代码格式
行长度
不超过80字符。(为了代码的美观和可读性)
正面例子:分行。
bool retval = DoSomething(argument1,argument2,
argument3,argument4,
argument5,argument6);
反面例子:全写在一行。
bool retval = DoSomething(argument1,argument2,argument3,argument4,argument5,argument6);
空格还是制表符
使用空格,而不是制表符(Tab键)。
缩进
2空格(4空格也可以)。
左大括号
左大括号放在行尾,不另起一行。
正面例子:
while (data + 4 <= limit){
uint_t += 4;
}
其他例子:
while (data + 4 <= limit)
{
uint_t += 4;
}
条件语句
if 和 else 另起一行。(条件语句、循环语句等,关键词新起一行,并且最好加上大括号)
正面例子:
if (a < b){ //圆括号与内部表达式之间没有空格
DoThis(); // 2 空格缩进。
}else{ // else与 if的右括号同一行。
DoThat();
}
反面例子:
if (a < b) DoThis(); // 不允许 - 当有 else 分支时 if 块写在同一行。
else DoThat();
圆括号
外侧无空格,内侧有空格。(注意:表达式还是有空格)
正面例子:
if (a < b) { // Good:圆括号外侧有空格,内侧无空格
DoThis();
}else{
DoThat();
}
反面例子:
if ( a < b ) { // Bad:圆括号内侧有空格
DoThis();
}else{
DoThat();
}
if(a < b) { // Bad:圆括号外侧无空格
DoThis();
}else{
DoThat();
}
横向留白
行尾无空格,赋值符号前有空格,一元操作符无空格。
正面例子:
while (data + 4 <= limit) {
uint32_t = DecodeFixed32(data);
data += 4;
h += w;
h *= m;
h ^= (h >> 16);
++x;
}
反面例子:
while (data + 4 <= limit){
uint32_t w = DecodeFixed32(data);
data += 4;
h += w;
h *= m;
h ^= (h >> 16);
++x;
} // Bad:行尾有空格。
while (data + 4 <= limit){
uint32_t w=DecodeFixed32(data); // Bad:赋值符号前后无空格。
data += 4;
h += w;
h *= m;
h ^= (h >> 16);
++x;
}
while (data + 4 <= limit){
uint32_t = DecodeFixed32(data);
data += 4;
h += w;
h *= m;
h ^= (h >> 16);
++ x; // Bad:一元操作符有空格。
}
纵向留白
函数内连续至多一行空格,函数间连续至多两行空格。
正面例子:
std::string NumberToString(uint64_t num){ // Good:垂直留白恰当
std::string r;
AppendNumberTo(&r, num);
return r;
}
std::string EscopeString(const Slice& value){
std::string r;
AppendEscapedStringTo(&r, value);
return r;
}
反面例子:
std::string NumberToString(uint64_t num){
std::string r;
// Bad:函数内没必要的空行
AppendNumberTo(&r, num);
return r;
}
std::string EscopeString(const Slice& value){
std::string r;
AppendEscapedStringTo(&r, value);
return r;
}
std::string NumberToString(uint64_t num){
std::string r;
AppendNumberTo(&r, num);
return r;
}
// Bad:函数间间隔超过两行。
std::string EscopeString(const Slice& value){
std::string r;
AppendEscapedStringTo(&r, value);
return r;
}
命名规则
基本原则
有意义,不缩写。(命名有意义,无缩写,不过分冗长)
正面例子:
int price_count_reader; // 无缩写
int num_errors; // “num”是一个常见的写法
int num_dns_connections; // 人人都知道 "DNS" 是什么
反面例子:
int a; // 毫无意义
int nerr; // 含糊不清的缩写
int n_comp_coons; // 含糊不清的缩写
int wgc_connections; // 只有贵团队知道什么意思
int pc_reader; // “pc” 有太多可能的解释,有歧义
int cstmr_id; // 删减了若干字母
用法要自然
for 循环变量用 i,计数变量可用 n 。
正面例子:
vector<int> price_list = ...;
for (int i = 0; i < price_list.size(); ++i) { // Good:for 循环搭配 i 是很正常的组合
DoSomething(price_list[i]);
}
反面例子:
vector<int> price_list = ...;
for (int price_index = 0; price_index < price_list.size(); ++price_index) { // Bad:没必要刻意用这样复杂的变量名。
DoSomething(price_list[price_index]);
}
类型命名
大驼峰式(帕斯卡命名法,每个单词的首字母都大写)。
正面例子:
class UrlTable {
...
}
变量命名
下划线式。(单词全部小写)
正面例子:
std::string table_name; // Good:下划线式。
类成员命名
下划线式+下划线结尾。
正面例子:
class TableInfo {
...
private:
std::string table_name_; // Good:下划线式 + 末尾_
}
结构体成员变量
下划线式。
常量名
k 开头的小驼峰式。(k 小写,后面每个单词首字母都大写)
正面例子:
const int kDaysInWeek = 7;
函数
大驼峰式。
宏
大写+下划线。(宏全部使用大写字母,并且用下划线连接)
正面例子:
#define PI_ROUNDED 3.0
注释
符号
// 和 /* 都可以,但要统一。
规则
// 之后要空一格。
位置
代码前或行尾。
行尾注释位置
行尾空两格再写 //
注释格式
首字母大写。
TODO
遗留工作写TODO,四个字母大写。
Google建议注释的地方
全局变量、类、自定义函数。
其他
变量声明位置
距离第一次使用尽可能近。(用的时候再创建变量,不要一进函数,就先把所有变量全都创建完)
变量初始化
声明和初始化尽量不要分开。(创建变量的时候就直接初始化)
循环体中变量声明
如果是对象,放在循环开始前声明。(避免重复调用构造和析构函数)
正面例子:
int j = g(); // Good:声明和初始化合并
Foo f; // Good:对象声明放在循环外。
for (int i = 0; i<100000; ++i) {
f.DoSomething(i);
}
反面例子:
int i;
i = f(); // Bad:初始化和声明分开
// 低效操作
for (int i = 0; i<100000; ++i) {
Foo f; // Bad:调用 100000 次构造和析构函数。
f.DoSomething(i);
}