强制使用花括号

17

我之前写过一份代码规范文件,其中规定“必须始终使用大括号来控制循环和条件代码块,即使(尤其是)只有一行代码。”

例如:

// this is wrong
if (foo) 
    //bar
else 
    //baz
while (stuff)
    //things

// This is right.
if (foo) {
    // bar
} else {
    // baz
}
while (things) {
    // stuff
}

如果你不在单行代码中使用大括号,然后有人将其注释掉,那么你就会遇到麻烦。如果你没有使用大括号来包围单行代码,并且缩进在其他人的机器上显示不同... 那么你就会遇到麻烦。

所以问题是:这个标准存在错误或者不合理的原因吗?目前已经有一些讨论,但是没有人能够提供比“看起来不好看”更好的反驳意见。


10
我觉得这是一个明智的标准 - 你提供了充分的理由,而且没有任何不利影响。 - anon
5
这可能应该是一个社区维基。 - Matthew Whited
4
我过去也一直这样做,没有例外。强制使用花括号的原因已经被所有人总结过了,所以我不会在这里重复。然而,我现在更加欣赏增加代码密度,而不是只有一种写if语句的方法。 - just somebody
2
我不会在同一行写}和else。如果它们在不同的行上,注释或删除else部分会更容易。 - nalply
2
这怎么不具有争议性呢?我的意思是,那是一个合理的标准,但在我看来,几乎任何关于花括号与否的讨论都属于宗教战争。 - Daniel Bingham
显示剩余6条评论
21个回答

23
我能提供的最好的反驳是,由于空格占用的额外行数减少了您一次可以看到的代码量,而一次可以看到的代码量是发现错误的难易程度的重要因素。我同意您提出的包括花括号的原因,但在多年的C++开发中,我只能想起一次犯错的情况,并且那个地方本来就没有跳过花括号的好理由。不幸的是,我不能告诉您在实际操作中是否看到那些额外的代码行有所帮助。
也许我更加偏袒匹配相同缩进级别的大括号的对称性(以及包含语句作为一个执行块的暗示分组),这意味着始终添加大括号会为项目添加很多行代码。

9
我更喜欢一页上有更多的代码行,这10年来我从未见过因此导致的错误。 - David
3
考虑在“if”后面加入一个调试打印语句。如果你没有使用大括号,那么此时if只会影响调试打印语句而不是它下面的其他语句。在调试代码时,我曾因不遵守花括号规则而踩过这个坑,不止一次。 - Nathan Fellman
我讨厌在同一行上使用大括号,因为它们很难跟踪。如果你将它们放在自己的一行上,那么屏幕上就会少一些代码。因此,在这种情况下,我从不使用它们,我总是使用缩进来表示控制级别。 - Loren Pechtel
4
在单行代码中使用大括号仅增加杂音,没有任何实际的好处。只要规则是在任何多于一行的代码周围使用大括号,或者如果结构(上面大括号前的if/while部分)超过单行。这包括注释等。也就是说,只有在最简单易读的情况下才可以省略大括号,因此缺少大括号不会引入任何危险。如果添加了注释或将if拆分成两行,则必须使用大括号! - Jason Williams
1
@Nathan,很容易就能发现大括号丢失了。当然,为了添加调试打印语句而重新添加它们需要更多的点击和按键,但并不是那么困难。我也曾经因为疲惫和状态不佳而被这个问题困扰过几次。但我总是把它看作是放下键盘、离开一会儿的信号,而不是改变我的代码风格标准的信号。 - Daniel Bingham
显示剩余2条评论

22

对于if语句,如果其结果为return或continue循环,则我会做一些小的例外,除此之外我会强制执行这个标准。

所以,按我的标准,以下是正确的:

if(true) continue;

就像这个样子

if(true) return;

但是规则是要么使用return或continue,并且它们必须在同一行上。否则,就需要用括号包裹。

这样做的原因既是为了有一个标准的做法,也是为了避免你提到的注释问题。


3
总是将continue或return语句放在下一行,但也许这只是我的习惯。 - Robert Harvey
1
我肯定可以理解“在同一行”的例外情况,我可能会将标准更改为该情况。(谢谢!) - Dean J
1
我遵循相同的标准;这是一个好的例外。在大括号中只有一个返回语句看起来很傻。 - xcut
1
好主意 - 我是一个括号的坚持者,但这是一个合理和有用的例外。 - Ray
2
而且,可以使用 if (true) break; 来终止循环。 - Jonathan Leffler
显示剩余4条评论

12

我认为这个规则过于严格。强制使用一种方法并不能培养出好的程序员,它只是降低了粗心大意者犯错的几率。

你提供的例子是有道理的,但是有比强制使用花括号更好的解决方案:

如果你不给单行语句加花括号,某个人注释掉时就会出现问题。

有两种做法可以更好地解决这个问题,请选择其中之一:

1)在单行语句前面的if、while等地方加注释。例如,请将:

if(foo)
    bar();

就像其他多行语句一样(例如,具有多行的赋值语句或多行函数调用):

//if(foo)
//    bar();

2)在//前加上;

if(foo)
;//    bar();

如果你没有为单行代码加上括号,且在别人的机器上缩进显示不一致……你就会遇到麻烦。

不是这样的,代码依然可用,但难以阅读。请修复缩进问题,选择使用制表符或空格并坚持使用。千万不要混合使用制表符和空格进行缩进,因为很多文本编辑器可以自动帮助您解决此问题。

写一些Python代码可以纠正一些不良缩进习惯。

另外,像} else {这样的结构对我来说看起来像TIE战斗机的nethack版本。

有没有好的理由可以证明这是一个错误或不合理的标准?虽然有一些讨论,但没有人能给出比“感觉难看”更好的反驳意见。

多余的大括号(和括号)是视觉上的杂物。视觉杂物会使代码变得难以阅读。代码越难以阅读,隐藏漏洞就越容易。

int x = 0;
while(x < 10);
{
    printf("Count: %d\n", ++x);
}

强制使用大括号并不能帮助找到上面代码中的错误。

P.S. 我是“每条规则都应该有其原因”的支持者,或者如达赖喇嘛所说,“要知道规则,才能正确地打破它们。”


1
强制使用大括号可以避免因为歧义而产生的错误。参考悬挂else问题。 - pestilence669
2
我不是独自工作的;这就是标准存在的全部原因。当注释掉某些内容时,我无法强制要求人们记住做某些特定的事情。但是,我可以强制执行一些容易检查的事情。 - Dean J
4
“视觉混乱”是不使用不必要的大括号的有效反驳理由。我也同意能够一次看到更多代码会更好。 - devuxer
6
@Pestilence:在if/else/elsif语句中强制使用一致性,也能消除悬挂else问题。但是,到处强制使用大括号有些过度。 - Matt Briggs
3
赞同减少视觉混乱。我希望人们停止在好的实践名义下使已经冗长的语言变得尽可能的冗长。 - Matt Briggs
显示剩余13条评论

8

我还没有听到任何一个不使用大括号的好理由。

我听到的任何“感觉丑陋”的理由都无法与其带来的好处相比。

编码规范的存在是为了让代码更易于阅读和减少错误。

这是一项真正值得付出的标准。


2
Robert;好处包括避免引入意外错误,使代码更易读。 - Dean J
9
这些只是有关于所获益处的观点,而非事实。 - Matthew Whited
4
十年来,我只遇到过一次由于省略花括号导致的bug,这就是为什么当条件语句的主体为空时,应该要求使用花括号和注释。在同样的十年时间里,我输入了许多花括号,也省略了更多。当从未因此导致过错误时,很难说添加所有这些花括号会"真正产生回报"。应该专注于那些确实有效的规则,例如避免在条件语句中使用不一致的双重或三重否定(在C++中有时会用到的!!被认为是一致的)。 - Sam Harwell
3
缺点是噪音。多余的代码并没有实际意义,只会让本来有意义的代码变得难以阅读。在一个刻意构造的示例中,这并不是什么大问题,但随着时间积累,问题会越来越明显。 - Matt Briggs
1
对于那些声称由于没有使用大括号而从未犯过错误的人...编码规范的主要原因之一是将所有代码库和所有程序员置于平等的基础上,无论经验水平如何。你可能是一个超级巫师编码员,但仅仅因为你理解你的代码并且你不会犯错,并不意味着接替你离开去更美好的地方的初级程序员会理解你的杰作。遵循编码规范展示了对继承你的代码的人的基本尊重。 - Jeffrey Hines
显示剩余7条评论

5
我认为大括号应该根据缩进来匹配。
// This is right.
if (foo) 
{
    // bar
}
else 
{
    // baz
}

while (things) 
{
    // stuff
}

就你提供的两个例子而言,我认为你的稍微不太容易阅读,因为找到匹配的右括号可能会比较困难,但在缩进不正确的情况下更易读,同时允许更容易地插入逻辑。这并没有太大的区别。
即使缩进不正确,if语句也将执行下一条命令,无论它是否在下一行。将两个命令放在同一行上的唯一原因是为了调试器支持。

1
我对大括号的风格没有偏好;我倾向于使用项目中已经更常见的那种来进行标准化。 - Dean J
1
是的。我讨厌没有对齐缩进的大括号。 - Loren Pechtel

5

我认为遵循编码规范以减少错误并使代码更易读是无可厚非的。虽然一开始可能会让一些人感到不舒服,但我认为这是完全有效的实施规则。


4

我的个人规则是,如果条件语句很短,则将其全部放在一行上:

if(!something) doSomethingElse();

通常只有在连续出现一堆像这样的if语句时,我才会使用它。

if(something == a) doSomething(a);
if(something == b) doSomething(b);
if(something == b) doSomething(c);

不过这种情况并不经常发生,所以除此之外,我总是使用大括号。


2
如果(!something){ doSomethingElse(); } //就是这样 - Joe Phillips
1
@d03boy,加了花括号的版本有什么优势呢?当只有一行代码时,“不小心注释掉”的论点并不适用。你的版本所做的只是增加了4个字符。 - tster
代码一致性更易于阅读(始终使用大括号的代码)。 - Joe Phillips
1
4个额外字符真的那么糟糕吗? - Joe Phillips
2
读取包含大括号的一行与正常的编码风格完全不一致。事实上,通常一个闭合大括号会单独占据一行。 - tster

4
我看到的一个大优势是,对于有括号的条件语句和循环语句,添加更多语句更容易,并且在开头创建括号不需要太多的按键操作。

4

目前,我与一个遵循这个标准的团队合作,虽然我对此持抵触态度,但为了统一性而遵守。

我反对禁止使用异常、模板或宏的团队,理由相同:如果你选择使用一种语言,就要使用整个语言。如果在C、C++和Java中花括号是可选的,那么通过惯例强制使用它们表明对语言本身有些恐惧。

我理解其他答案中描述的危险,并理解对统一性的渴望,但我不赞同语言子集,除非存在某些严格的技术原因,例如某些环境中唯一的编译器不支持模板,或者与C代码的交互阻止广泛使用异常。

我的大部分时间都用来审核初级程序员提交的更改,常见的问题与花括号的位置或语句放错地方无关。这种危险被夸大了。我宁愿把时间花在解决更重要的问题上,而不是寻找编译器可以轻松接受的违规行为。


3
标准支架的意义在于您不必再考虑它,可以将更多时间花在更重要的问题上。 - anon

4
只有将规则数量最小化,编程规范才能被一组程序员很好地遵循。要权衡收益与成本(每个额外的规则都会使程序员感到困惑,当超过某个阈值时,实际上会减少程序员遵循任何规则的机会)。因此,制定编码标准需要做到以下几点:
- 确保您可以用清晰的证据证明每个规则比替代方案更好。 - 查看规则的替代方案——它真的必要吗?如果您的所有程序员都很好地使用空格(空行和缩进),if语句很容易阅读,并且即使是初学者也不可能将if语句中的语句误认为是独立的语句。如果您遇到了很多与if作用域相关的错误,则根本原因可能是您的白空格/缩进样式很差,使得代码不必要地难以阅读。 - 根据其对代码质量的可衡量影响来优先考虑规则的重要性。通过强制执行规则(例如“始终检查null”,“始终使用assert验证参数”,“始终编写单元测试”与“始终添加一些括号即使它们不需要”),您可以避免多少个错误?前者规则每年可以为您节省数千个错误。括号规则可能只会为您节省一个错误。也许。 - 保留最有效的规则,并丢弃无用的规则。无用的规则至少是任何忽略该规则可能导致的任何错误成本都更高的规则。但如果您有超过30个关键规则,您的程序员可能会忽略其中的许多规则,您的良好意图将变得毫无意义。 - 解雇任何随意注释掉代码而不阅读它的程序员 :-) P.S. 我对大括号的立场是:如果“if”语句或其内容都是单行,则可以省略大括号。这意味着,如果您有一个包含一行注释和一行代码的if语句,则内容占据两行,因此需要大括号。如果if条件跨越两行(即使内容只有一行),则需要大括号。这意味着您仅在微不足道、简单、易于阅读且实际上不会出现错误的情况下省略大括号。(当语句为空时,我不使用大括号,但我总是放置一个明确说明它为空的注释,并且是故意的。但这已经涉及到了一个不同的主题:在代码中明确表达,以便读者知道您的作用域是空的,而不是电话响了,您忘记完成代码。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接