服务端组件C++代码规范
前言:
规则的作用是避免混乱,每个人的代码风格都不一样,但是一个团队如果没有统一的标准,后续人员进行二次开发或者维护效率会比较低。
- 命名规则
1.1类型命名
类类型名称的每个单词首字母均大写, 不包含下划线: Game,GameLogic。
变量命名第一个首字母小写,后面大写:tmpHandCardList,chairId。
成员变量在变量命名的基础上加m_:m_handCards, m_curChairId。
函数名的每个单词首字母大写 , “驼峰变量名”如:HandleOutCardOpcode。
宏的命名,全大写,下划线分割:MY_MACRO_THAT_SCARES_SMALL_CHILDREN.
1.2 缩写
函数命名, 变量命名, 文件命名要有描述性; 少用缩写.
尽可能使用描述性的命名, 别心疼空间, 毕竟相比之下让代码易于新读者理解更重要. 不要用只有项目开发者能理解的缩写, 也不要通过砍掉几个字母来缩写单词.
错误示例:
int n; // 毫无意义.
int nerr; // 含糊不清的缩写.
int n_comp_conns; // 含糊不清的缩写.
正确示例:
int baseScore; // 无缩写
int endPlayerNum; // "num" 是一个常见的写法
一些特定的广为人知的缩写是允许的, 例如用 i 表示迭代变量.
如
使用单层循环的时候可以使用i缩写,即使使用i,循环的作用也一目了然。
for (int i = 0; i < GAME_PLAYER; i++)
{
if(i==m_turnWinChairId)
{
return;
}
}
注:,但是使用多层循环的时候最好使用带有实际意义的变量名,如
for (int chairId = 0; chairId < GAME_PLAYER; chairId ++)
{
for(int tmpIndex=0; tmpIndex<m_handCards[chairId].size();tmpIndex++)
{
if(m_handCards[chairId][tmpIndex]==0X12)
{
}
}
}
假如此时再使用i,会使得代码的可读性变得非常差。
1.3变量的声明和定义
基本的原则:尽可能小的作用域中声明变量, 离第一次使用越近越好. 这使得代码浏览者更容易定位变量声明的位置。
但也有特殊的情况。
// 低效的实现
for (int i = 0; i < 1000000; ++i)
{
Foo f; // 构造函数和析构函数分别调用 1000000 次!
f.DoSomething(i);
}
// 高效的实现
Foo f; // 构造函数和析构函数只调用 1 次
for (int i = 0; i < 1000000; ++i)
{
f.DoSomething(i);
}
应使用初始化的方式替代声明再赋值。
int i;
i = f(); // 坏——初始化和声明分离
int j = g(); // 好——初始化时声明
- 函数
*大括号另起一行
2.1函数的参数顺序为: 输入参数在先, 后跟输出参数. 在排列参数顺序时, 将所有的输入参数置于输出参数之前.特别要注意, 在加入新参数时不要因为它们是新参数就置于参数列表最后, 而是仍然要按照前述的规则, 即将新的输入参数也置于输出参数之前.
2.2尽量编写简短, 凝练的函数. 如果函数超过 40 行, 可以思索一下能不能在不影响程序结构的前提下对其进行分割.即使一个长函数现在工作的非常好, 一旦有人对其修改, 有可能出现新的问题, 甚至导致难以发现的 bug. 使函数尽量简短, 以便于他人阅读和修改代码. 分割为更简短的函数更易于管理和维护.
- 注释
*注释推荐使用//
*在代码块前写注释
最好的代码应当本身就是文档. 有意义的类型名和变量名, 要远胜过要用注释解释的含糊不清的名字,但是实际上写代码的时候总会有一些因素会导致部分代码较为难懂,注释作为一种补充,虽然写起来很痛苦, 但对保证代码可读性至关重要.回想一下你在阅读一份没有注释的代码时的痛苦,所以不要吝啬。
3.1每个类的定义都要附带一份注释, 描述类的功能和用法, 除非它的功能相当明显.Game和GameLogic这种就不需要,自己定义新的class或struct时需要定义。
3.2每个类数据成员 (也叫实例变量或成员变量) 都应该用注释说明用途. 如果变量类型与变量名已经足以描述一个变量, 那么就不再需要加上注释.如bool m_maskRevolutionFlag[GAME_PLAYER] 玩家选择革命的标志,这种游戏特有的变量需要注释,而 uint8_t endPlayerCount;明显能从名称看出是结束玩家数量,就不需要写注释
3.3每个函数声明处前都应当加上注释, 描述函数的功能和用途. 只有在函数的功能简单而明显时才能省略这些注释(例如, GetCardLogicValue()).
3.4函数定义处,如果函数的实现过程中用到了很巧妙的或者很复杂的方式, 那么在函数定义处应当加上解释性的注释. 例如, 你所使用的编程技巧, 实现的大致步骤。
3.5逻辑较为复杂的部分或者多层循环的时候,以及使用了位操作等较为少见的操作时,需要注释,如。
//通过玩家手牌是否空和是否被闷寻找下一个出牌的chairid
for(uint16_t i = 1; i < GAME_PLAYER;i++)
{
uint16_t tmpChairId = (chairId + i) % GAME_PLAYER;
if(m_handCards[i].size()>0&&!m_playerMenFlag.test(i))
return tmpChairId;
}
3.6如果函数参数的意义不明显,可以增加参数注释增加代码的可读性。
3.7错误例子:
// 寻找vector中的element元素
auto iter = std::find(v.begin(), v.end(), element);
if (iter != v.end())
{
Process(element);
}
这种显而意见的地方就不需要注释。
总之,在不通用,比较冷门,逻辑复杂的地方写上注释,相信大家只要稍微花上一点心思,就可以令代码的可读性更好。
- 总结
因为写代码时遇到各种情况,肯定做不到100%规范,希望大家的代码风格往规范上靠拢,如果有好的建议或者规范中有不好的地方,也欢迎大家一起讨论。