您的位置:首页 > 编程语言 > C语言/C++

Google C++编程风格指南(七):格式

2009-12-07 16:27 309 查看
格式

代码风格和格式确实比较随意,但一个项目中所有人遵循同一风格是非常容易的,作为个人未必同意下述格式规则的每一处,但整个项目服从统一的编程风格是很重要的,这样做才能让所有人在阅读和理解代码时更加容易。

1.行长度(LineLength)

每一行代码字符数不超过80。

我们也认识到这条规则是存有争议的,但如此多的代码都遵照这一规则,我们感觉一致性更重要。

优点:提倡该原则的人认为强迫他们调整编辑器窗口大小很野蛮。很多人同时并排开几个窗口,根本没有多余空间拓宽某个窗口,人们将窗口最大尺寸加以限定,一致使用80列宽,为什么要改变呢?

缺点:反对该原则的人则认为更宽的代码行更易阅读,80列的限制是上个世纪60年代的大型机的古板缺陷;现代设备具有更宽的显示屏,很轻松的可以显示更多代码。

结论:80个字符是最大值。例外:

1)如果一行注释包含了超过80字符的命令或URL,出于复制粘贴的方便可以超过80字符;

2)包含长路径的可以超出80列,尽量避免;

3)头文件保护(防止重复包含第一篇)可以无视该原则。

2.非ASCII字符(Non-ASCIICharacters)

尽量不使用非ASCII字符,使用时必须使用UTF-8格式。

哪怕是英文,也不应将用户界面的文本硬编码到源代码中,因此非ASCII字符要少用。特殊情况下可以适当包含此类字符,如,代码分析外部数据文件时,可以适当硬编码数据文件中作为分隔符的非ASCII字符串;更常用的是(不需要本地化的)单元测试代码可能包含非ASCII字符串。此类情况下,应使用UTF-8格式,因为很多工具都可以理解和处理其编码,十六进制编码也可以,尤其是在增强可读性的情况下——如
"/xEF/xBB/xBF"
是Unicode的zero-widthno-breakspace字符,以UTF-8格式包含在源文件中是不可见的。

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
}


______________________________________
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: