Google C++编程风格指南(七):格式
2009-10-10 19:28
543 查看
1.行宽原则上不超过80列,把22寸的显示屏都占完,怎么也说不过去;2.尽量不使用非ASCII字符;3.UNIX/Linux下无条件使用空格,MSVC的话使用Tab也无可厚非;4.函数参数、逻辑条件、初始化列表:要么所有参数和函数名放在同一行,要么所有参数并排分行……
格式
代码风格和格式确实比较随意,但一个项目中所有人遵循同一风格是非常容易的,作为个人未必同意下述格式规则的每一处,但整个项目服从统一的编程风格是很重要的,这样做才能让所有人在阅读和理解代码时更加容易。
1.行长度(LineLength)
每一行代码字符数不超过80。
我们也认识到这条规则是存有争议的,但如此多的代码都遵照这一规则,我们感觉一致性更重要。
优点:提倡该原则的人认为强迫他们调整编辑器窗口大小很野蛮。很多人同时并排开几个窗口,根本没有多余空间拓宽某个窗口,人们将窗口最大尺寸加以限定,一致使用80列宽,为什么要改变呢?
缺点:反对该原则的人则认为更宽的代码行更易阅读,80列的限制是上个世纪60年代的大型机的古板缺陷;现代设备具有更宽的显示屏,很轻松的可以显示更多代码。
结论:80个字符是最大值。例外:
1)如果一行注释包含了超过80字符的命令或URL,出于复制粘贴的方便可以超过80字符;
2)包含长路径的可以超出80列,尽量避免;
3)头文件保护(防止重复包含
2.非ASCII字符(Non-ASCIICharacters)
尽量不使用非ASCII字符,使用时必须使用
哪怕是英文,也不应将用户界面的文本硬编码到源代码中,因此非ASCII字符要少用。特殊情况下可以适当包含此类字符,如,代码分析外部数据文件时,可以适当硬编码数据文件中作为分隔符的非ASCII字符串;更常用的是(不需要本地化的)单元测试代码可能包含非ASCII字符串。此类情况下,应使用UTF-8格式,因为很多工具都可以理解和处理其编码,十六进制编码也可以,尤其是在增强可读性的情况下——如
"/xEF/xBB/xBF"是Unicode的
3.空格还是制表位(Spacesvs.Tabs)
只使用空格,每次缩进2个空格。
使用空格进行缩进,不要在代码中使用tabs,设定编辑器将tab转为空格。
4.函数声明与定义(FunctionDeclarationsandDefinitions)
返回类型和函数名在同一行,合适的话,参数也放在同一行。
函数看上去像这样:
ReturnTypeClassName::FunctionName(Typepar_name1,Typepar_name2){ DoSomething(); ... }
如果同一行文本较多,容不下所有参数:
ReturnTypeClassName::ReallyLongFunctionName(Typepar_name1, Typepar_name2, Typepar_name3){ DoSomething(); ... }
甚至连第一个参数都放不下:
ReturnTypeLongClassName::ReallyReallyReallyLongFunctionName( Typepar_name1,//4spaceindent Typepar_name2, Typepar_name3){ DoSomething();//2spaceindent ... }
注意以下几点:
1)返回值总是和函数名在同一行;
2)左圆括号(openparenthesis)总是和函数名在同一行;
3)函数名和左圆括号间没有空格;
4)圆括号与参数间没有空格;
5)左大括号(opencurlybrace)总在最后一个参数同一行的末尾处;
6)右大括号(closecurlybrace)总是单独位于函数最后一行;
7)右圆括号(closeparenthesis)和左大括号间总是有一个空格;
8)函数声明和实现处的所有形参名称必须保持一致;
9)所有形参应尽可能对齐;
10)缺省缩进为2个空格;
11)独立封装的参数保持4个空格的缩进。
如果函数为
const的,关键字
const应与最后一个参数位于同一行。
//Everythinginthisfunctionsignaturefitsonasingleline ReturnTypeFunctionName(Typepar)const{ ... } //Thisfunctionsignaturerequiresmultiplelines,but //theconstkeywordisonthelinewiththelastparameter. ReturnTypeReallyLongFunctionName(Typepar1, Typepar2)const{ ... }
如果有些参数没有用到,在函数定义处将参数名注释起来:
//Alwayshavenamedparametersininterfaces. classShape{ public: virtualvoidRotate(doubleradians)=0; } //Alwayshavenamedparametersinthedeclaration. classCircle:publicShape{ public: virtualvoidRotate(doubleradians); } //Commentoutunusednamedparametersindefinitions. voidCircle::Rotate(double/*radians*/){}
//Bad-ifsomeonewantstoimplementlater,it'snotclearwhatthe //variablemeans. voidCircle::Rotate(double){}
译者注:关于UNIX/Linux风格为什么要把左大括号置于行尾(.cc文件的函数实现处,左大括号位于行首),我的理解是代码看上去比较简约,想想行首除了函数体被一对大括号封在一起之外,只有右大括号的代码看上去确实也舒服;Windows风格将左大括号置于行首的优点是匹配情况一目了然。
5.函数调用(FunctionCalls)
尽量放在同一行,否则,将实参封装在圆括号中。
函数调用遵循如下形式:
boolretval=DoSomething(argument1,argument2,argument3);
如果同一行放不下,可断为多行,后面每一行都和第一个实参对齐,左圆括号后和右圆括号前不要留空格:
boolretval=DoSomething(averyveryveryverylongargument1, argument2,argument3);
如果函数参数比较多,可以出于可读性的考虑每行只放一个参数:
boolretval=DoSomething(argument1, argument2, argument3, argument4);
如果函数名太长,以至于超过行最大长度,可以将所有参数独立成行:
if(...){ ... ... if(...){ DoSomethingThatRequiresALongFunctionName( very_long_argument1,//4spaceindent argument2, argument3, argument4); }
6.条件语句(Conditionals)
更提倡不在圆括号中添加空格,关键字
else另起一行。
对基本条件语句有两种可以接受的格式,一种在圆括号和条件之间有空格,一种没有。
最常见的是没有空格的格式,那种都可以,还是一致性为主。如果你是在修改一个文件,参考当前已有格式;如果是写新的代码,参考目录下或项目中其他文件的格式,还在徘徊的话,就不要加空格了。
if(condition){//nospacesinsideparentheses ...//2spaceindent. }else{//Theelsegoesonthesamelineastheclosingbrace. ... }
如果你倾向于在圆括号内部加空格:
if(condition){//spacesinsideparentheses-rare ...//2spaceindent. }else{//Theelsegoesonthesamelineastheclosingbrace. ... }
注意所有情况下
if和左圆括号间有个空格,右圆括号和左大括号(如果使用的话)间也要有个空格:
if(condition)//Bad-spacemissingafterIF. if(condition){//Bad-spacemissingbefore{. if(condition){//Doublybad.
if(condition){//Good-properspaceafterIFandbefore{.
有些条件语句写在同一行以增强可读性,只有当语句简单并且没有使用
else子句时使用:
if(x==kFoo)returnnewFoo(); if(x==kBar)returnnewBar();
如果语句有
else分支是不允许的:
//Notallowed-IFstatementononelinewhenthereisanELSEclause if(x)DoThis(); elseDoThat();
通常,单行语句不需要使用大括号,如果你喜欢也无可厚非,也有人要求
if必须使用大括号:
if(condition) DoSomething();//2spaceindent. if(condition){ DoSomething();//2spaceindent. }
但如果语句中哪一分支使用了大括号的话,其他部分也必须使用:
//Notallowed-curlyonIFbutnotELSE if(condition){ foo; }else bar; //Notallowed-curlyonELSEbutnotIF if(condition) foo; else{ bar; }
//CurlybracesaroundbothIFandELSErequiredbecause
//oneoftheclausesusedbraces.
if(condition){
foo;
}else{
bar;
}
7.循环和开关选择语句(LoopsandSwitchStatements)
switch语句可以使用大括号分块;空循环体应使用
{}或
continue。
switch语句中的
case块可以使用大括号也可以不用,取决于你的喜好,使用时要依下文所述。
如果有不满足
case枚举条件的值,要总是包含一个
default(如果有输入值没有
case去处理,编译器将报警)。如果
default永不会执行,可以简单的使用
assert:
switch(var){
case0:{//2spaceindent
...//4spaceindent
break;
}
case1:{
...
break;
}
default:{
assert(false);
}
}
空循环体应使用
{}或
continue,而不是一个简单的分号:
while(condition){
//Repeattestuntilitreturnsfalse.
}
for(inti=0;i<kSomeNumber;++i){}//Good-emptybody.
while(condition)continue;//Good-continueindicatesnologic.
while(condition);//Bad-lookslikepartofdo/whileloop.
8.指针和引用表达式(PointersandReferenceExpressions)
句点(
.)或箭头(
->)前后不要有空格,指针/地址操作符(
*、&)后不要有空格。
下面是指针和引用表达式的正确范例:
x=*p;
p=&x;
x=r.y;
x=r->y;
注意:
1)在访问成员时,句点或箭头前后没有空格;
2)指针操作符
*或
&后没有空格。
在声明指针变量或参数时,星号与类型或变量名紧挨都可以:
//Thesearefine,spacepreceding.
char*c;
conststring&str;
//Thesearefine,spacefollowing.
char*c;//butremembertodo"char*c,*d,*e,...;"!
conststring&str;
char*c;//Bad-spacesonbothsidesof*
conststring&str;//Bad-spacesonbothsidesof&
同一个文件(新建或现有)中起码要保持一致。
译者注:个人比较习惯与变量紧挨的方式。
9.布尔表达式(BooleanExpressions)
如果一个布尔表达式超过标准行宽(80字符),如果断行要统一一下。
下例中,逻辑与(
&&)操作符总位于行尾:
if(this_one_thing>this_other_thing&&
a_third_thing==a_fourth_thing&&
yet_another&last_one){
...
}
两个逻辑与(
&&)操作符都位于行尾,可以考虑额外插入圆括号,合理使用的话对增强可读性是很有帮助的。
译者注:个人比较习惯逻辑运算符位于行首,逻辑关系一目了然,各人喜好而已,至于加不加圆括号的问题,如果你对优先级了然于胸的话可以不加,但可读性总是差了些。
10.函数返回值(ReturnValues)
return表达式中不要使用圆括号。
函数返回时不要使用圆括号:
returnx;//notreturn(x);
11.变量及数组初始化(VariableandArrayInitialization)
选择
=还是
()。
需要做二者之间做出选择,下面的形式都是正确的:
intx=3;
intx(3);
stringname("SomeName");
stringname="SomeName";
12.预处理指令(PreprocessorDirectives)
预处理指令不要缩进,从行首开始。
即使预处理指令位于缩进代码块中,指令也应从行首开始。
//Good-directivesatbeginningofline
if(lopsided_score){
#ifDISASTER_PENDING//Correct--Startsatbeginningofline
DropEverything();
#endif
BackToNormal();
}
//Bad-indenteddirectives
if(lopsided_score){
#ifDISASTER_PENDING//Wrong!The"#if"shouldbeatbeginningofline
DropEverything();
#endif//Wrong!Donotindent"#endif"
BackToNormal();
}
13.类格式(ClassFormat)
声明属性依次序是
public:、
protected:、
private:,每次缩进1个空格(译者注,为什么不是两个呢?也有人提倡
private在前,对于声明了哪些数据成员一目了然,还有人提倡依逻辑关系将变量与操作放在一起,都有道理
:-))。
类声明(对类注释不了解的话,参考
classMyClass:publicOtherClass{
public://Notethe1spaceindent!
MyClass();//Regular2spaceindent.
explicitMyClass(intvar);
~MyClass(){}
voidSomeFunction();
voidSomeFunctionThatDoesNothing(){
}
voidset_some_var(intvar){some_var_=var;}
intsome_var()const{returnsome_var_;}
private:
boolSomeInternalFunction();
intsome_var_;
intsome_other_var_;
DISALLOW_COPY_AND_ASSIGN(MyClass);
};
注意:
1)所以基类名应在80列限制下尽量与子类名放在同一行;
2)关键词
public:、
protected:、
private:要缩进1个空格(译者注,MSVC多使用tab缩进,且这三个关键词没有缩进);
3)除第一个关键词(一般是
public)外,其他关键词前空一行,如果类比较小的话也可以不空;
4)这些关键词后不要空行;
5)
public放在最前面,然后是
protected和
private;
6)关于声明次序参考
14.初始化列表(InitializerLists)
构造函数初始化列表放在同一行或按四格缩进并排几行。
两种可以接受的初始化列表格式:
//Whenitallfitsononeline:
MyClass::MyClass(intvar):some_var_(var),some_other_var_(var+1){
或
//Whenitrequiresmultiplelines,indent4spaces,puttingthecolonon
//thefirstinitializerline:
MyClass::MyClass(intvar)
:some_var_(var),//4spaceindent
some_other_var_(var+1){//linedup
...
DoSomething();
...
}
15.命名空间格式化(NamespaceFormatting)
命名空间内容不缩进。
命名空间不添加额外缩进层次,例如:
namespace{
voidfoo(){//Correct.Noextraindentationwithinnamespace.
...
}
}//namespace
不要缩进:
namespace{
//Wrong.Indentedwhenitshouldnotbe.
voidfoo(){
...
}
}//namespace
16.水平留白(HorizontalWhitespace)
水平留白的使用因地制宜。不要在行尾添加无谓的留白。
普通:
voidf(boolb){//Openbracesshouldalwayshaveaspacebeforethem.
...
inti=0;//Semicolonsusuallyhavenospacebeforethem.
intx[]={0};//Spacesinsidebracesforarrayinitializationare
intx[]={0};//optional.Ifyouusethem,putthemonbothsides!
//Spacesaroundthecolonininheritanceandinitializerlists.
classFoo:publicBar{
public:
//Forinlinefunctionimplementations,putspacesbetweenthebraces
//andtheimplementationitself.
Foo(intb):Bar(),baz_(b){}//Nospacesinsideemptybraces.
voidReset(){baz_=0;}//Spacesseparatingbracesfromimplementation.
...
添加冗余的留白会给其他人编辑时造成额外负担,因此,不要加入多余的空格。如果确定一行代码已经修改完毕,将多余的空格去掉;或者在专门清理空格时去掉(确信没有其他人在使用)。
循环和条件语句:
if(b){//Spaceafterthekeywordinconditionsandloops.
}else{//Spacesaroundelse.
}
while(test){}//Thereisusuallynospaceinsideparentheses.
switch(i){
for(inti=0;i<5;++i){
switch(i){//Loopsandconditionsmayhavespacesinside
if(test){//parentheses,butthisisrare.Beconsistent.
for(inti=0;i<5;++i){
for(;i<5;++i){//Forloopsalwayshaveaspaceafterthe
...//semicolon,andmayhaveaspacebeforethe
//semicolon.
switch(i){
case1://Nospacebeforecoloninaswitchcase.
...
case2:break;//Useaspaceafteracolonifthere'scodeafterit.
操作符:
x=0;//Assignmentoperatorsalwayshavespacesaround
//them.
x=-5;//Nospacesseparatingunaryoperatorsandtheir
++x;//arguments.
if(x&&!y)
...
v=w*x+y/z;//Binaryoperatorsusuallyhavespacesaroundthem,
v=w*x+y/z;//butit'sokaytoremovespacesaroundfactors.
v=w*(x+z);//Parenthesesshouldhavenospacesinsidethem.
模板和转换:
vector<string>x;//Nospacesinsidetheangle
y=static_cast<char*>(x);//brackets(<and>),before
//<,orbetween>(inacast.
vector<char*>x;//Spacesbetweentypeandpointerare
//okay,butbeconsistent.
set<list<string>>x;//C++requiresaspacein>>.
set<list<string>>x;//Youmayoptionallymakeuse
//symmetricspacingin<<.
17.垂直留白(VerticalWhitespace)
垂直留白越少越好。
这不仅仅是规则而是原则问题了:不是非常有必要的话就不要使用空行。尤其是:不要在两个函数定义之间空超过2行,函数体头、尾不要有空行,函数体中也不要随意添加空行。
基本原则是:同一屏可以显示越多的代码,程序的控制流就越容易理解。当然,过于密集的代码块和过于疏松的代码块同样难看,取决于你的判断,但通常是越少越好。
函数头、尾不要有空行:
voidFunction(){
//Unnecessaryblanklinesbeforeandafter
}
代码块头、尾不要有空行:
while(condition){
//Unnecessaryblanklineafter
}
if(condition){
//Unnecessaryblanklinebefore
}
if-else块之间空一行还可以接受:
if(condition){
//Somelinesofcodetoosmalltomovetoanotherfunction,
//followedbyablankline.
}else{
//Anotherblockofcode
}
______________________________________
译者:首先说明,对于代码格式,因人、因系统各有优缺点,但同一个项目中遵循同一标准还是有必要的:
1.行宽原则上不超过80列,把22寸的显示屏都占完,怎么也说不过去;
2.尽量不使用非ASCII字符,如果使用的话,参考UTF-8格式(尤其是UNIX/Linux下,Windows下可以考虑宽字符),尽量不将字符串常量耦合到代码中,比如独立出资源文件,这不仅仅是风格问题了;
3.UNIX/Linux下无条件使用空格,MSVC的话使用Tab也无可厚非;
4.函数参数、逻辑条件、初始化列表:要么所有参数和函数名放在同一行,要么所有参数并排分行;
5.除函数定义的左大括号可以置于行首外,包括函数/类/结构体/枚举声明、各种语句的左大括号置于行尾,所有右大括号独立成行;
6../->操作符前后不留空格,*/&不要前后都留,一个就可,靠左靠右依各人喜好;
7.预处理指令/命名空间不使用额外缩进,类/结构体/枚举/函数/语句使用缩进;
8.初始化用=还是()依个人喜好,统一就好;
9.return不要加();
10.水平/垂直留白不要滥用,怎么易读怎么来。
来自:
相关文章推荐
- Google C++Style Guide【C++编程风格指南解读】——C++代码格式
- Google C++编程风格指南(七):格式
- Google C++编程风格指南(七):格式(转载)
- Google C++编程风格指南(七):格式
- Google_C++编程风格指南
- Google C++编程风格指南
- Google C++编程风格指南
- [译]Google C++编程风格指南(四)
- Google C++编程风格指南(一):头文件
- Google C++编程风格指南(八):规则之例外
- Google C++编程风格指南(三):C++ 类
- GoogleCpp风格指南 8)格式 _part2
- Google C++编程风格指南(四):智能指针和其他C++特性
- Google C++编程风格指南(八):规则之例外(转载)
- Google C++编程风格指南(四):智能指针和其他C++特性
- 读书笔记 |Google C++编程风格指南
- Google C++Style Guide【C++编程风格指南解读】——命名约定
- Google C++编程风格指南
- Google C++Style Guide【C++编程风格指南解读】——规则的根本目标
- Google C++编程风格指南(一)之头文件的相关规范