对于单行if或循环使用大括号(即{})的目的是什么?

时间:2012-08-30 08:50:10

标签: c++ c coding-style curly-braces defensive-programming

我正在阅读我的C ++讲师的一些讲义,他写了以下内容:

  
      
  1. 使用缩进//确定
  2.   
  3. 永远不要依赖运营商优先级 - 始终使用括号//确定
  4.   
  5. 始终使用{}块 - 即使只有一行// 不行,为什么???
  6.   
  7. 比较左侧的Const对象//确定
  8.   
  9. 对于> = 0 //漂亮技巧
  10. 的变量使用无符号   
  11. 删除后将指针设置为NULL - 双删除保护//不错
  12.   

第三种技术对我来说并不清楚:通过放入一行可以获得什么 一个{ ... }

例如,请使用这个奇怪的代码:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

并将其替换为:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;

使用第一版有什么好处?

23 个答案:

答案 0 :(得分:504)

当我们增加i时,我们会尝试修改j

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
        i++;

哦不!来自Python,这看起来不错,但实际上并非如此,因为它等同于:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

当然,这是一个愚蠢的错误,但即使是经验丰富的程序员也可以做错。

ta.speot.is's answer中指出了另一个非常好的理由

我能想到的第三个是嵌套的if

if (cond1)
   if (cond2) 
      doSomething();

现在,假设您现在想要在doSomethingElse()未满足时cond1(新功能)。所以:

if (cond1)
   if (cond2) 
      doSomething();
else
   doSomethingElse();

这显然是错误的,因为else与内部if相关联。


编辑:由于这引起了一些关注,我将澄清我的观点。我回答的问题是:

  

使用第一个版本有什么好处?

我已经描述过了。有一些好处。但是,IMO,“永远”规则并不总是适用。所以我不完全支持

  

总是使用{}块 - 即使是单行//不行,为什么???

我不是说总是使用{}块。如果这是一个简单的条件&amp;行为,不要。如果你怀疑有人可能会在晚些时候进来更改你的代码以添加功能,做。

答案 1 :(得分:316)

如果您不使用{},则很容易通过评论意外更改控制流。例如:

if (condition)
  do_something();
else
  do_something_else();

must_always_do_this();

如果您使用单行注释发表评论do_something_else(),您最终会得到以下结果:

if (condition)
  do_something();
else
  //do_something_else();

must_always_do_this();

它编译,但并不总是调用must_always_do_this()

我们在代码库中遇到了这个问题,有人在发布之前很快就禁用了某些功能。幸运的是,我们在代码审查中发现了它。

答案 2 :(得分:60)

我怀疑讲师的能力。考虑他的 分:

  1. 有人真的会写(或想要阅读)(b*b) - ((4*a)*c)吗? 一些优先级是显而易见的(或应该是),以及额外的括号 只是增加了混乱。 (另一方面,你_should_使用 在不太明显的情况下括号,即使你知道它们不是 必要的。)
  2. 排序。格式化有两种广泛的传播约定 条件和循环:
    if ( cond ) {
        code;
    }
    
    和:
    if ( cond )
    {
        code;
    }
    
    首先,我同意他的看法。开场{不可见, 所以最好假设它总是在那里。然而,在第二个,我 (和我一起工作的大多数人)没有问题 单个陈述的大括号。 (当然,提供了 缩进是系统的,你一贯地使用这种风格。 (还有很多非常优秀的程序员,编写非常易读的代码,省略 即使格式化第一种方式,也可以使用大括号。)
  3. NO 的。像if ( NULL == ptr )这样的事情很难以阻止 可读性。直观地写下比较。 (在很多情况下 导致右边的常数。)他的4是不好的建议;什么 这使得代码不自然使得它的可读性降低。
  4. NO 的。除int之外的任何内容都保留用于特殊情况。至 经验丰富的C和C ++程序员,使用unsigned信号位 运营商。 C ++没有真正的基数类型(或任何其他类型) 有效的子范围类型); unsigned不适用于数值, 因为促销规则。没有的数值 算术运算有意义,就像序列号一样 大概是unsigned。然而,我反对它,因为它 发送错误的消息:按位操作也没有意义。 基本规则是整数类型是int,_unless_有一个 使用其他类型的重要原因。
  5. NO 的。系统地这样做是误导,实际上并没有 防止任何事情。在严格的OO代码中,delete this;经常出现 最常见的情况(您无法将this设置为NULL),以及 否则,大多数delete都在析构函数中,因此您无法访问 无论如何后来指针。将其设置为NULL并没有做任何事情 关于任何其他浮动的指针。设置指针 系统地NULL给出了一种虚假的安全感,而不是 真的买你什么的。
  6. 查看任何典型参考文献中的代码。 Stroustrup违反了 例如,除了第一个规则之外,你给出的每条规则都是。

    我建议你找另一位讲师。一个谁知道什么 他正在谈论。

答案 3 :(得分:46)

所有其他答案都捍卫了你的讲师规则3.

我说我同意你的看法:规则多余,我不会建议。确实,如果你总是添加大括号,理论上可以防止错误。另一方面,我从未在现实生活中遇到过这个问题:与其他答案所暗示的相反,我不会忘记在必要时添加花括号。如果你使用适当的缩进,很明显你需要在多个语句缩进时添加大括号。

“组件10”的答案实际上突出了唯一可以想象的情况,这可能会导致错误。但另一方面,通过正则表达式替换代码总是需要非常小心。

现在让我们看一下奖牌的另一面:缺点是否始终使用大括号?其他答案完全忽略了这一点。但 是一个缺点:它占用了大量的垂直屏幕空间,这反过来会使你的代码无法读取,因为这意味着你必须滚动超过必要的。

考虑一个开头有很多保护条款的函数(是的,以下是糟糕的C ++代码,但在其他语言中这是一种非常常见的情况):

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
    {
        throw null_ptr_error("a");
    }
    if (b == nullptr)
    {
        throw null_ptr_error("b");
    }
    if (a == b)
    {
        throw logic_error("Cannot do method on identical objects");
    }
    if (not a->precondition_met())
    {
        throw logic_error("Precondition for a not met");
    }

    a->do_something_with(b);
}

这是一个可怕的代码,我坚决认为以下内容更具可读性:

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
        throw null_ptr_error("a");
    if (b == nullptr)
        throw null_ptr_error("b");
    if (a == b)
        throw logic_error("Cannot do method on identical objects");
    if (not a->precondition_met())
        throw logic_error("Precondition for a not met");

    a->do_something_with(b);
}

类似地,短嵌套循环可以从省略大括号中获益:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
        for (auto j = 0; j < a.h(); ++j)
            c(i, j) = a(i, j) + b(i, j);

    return c;
}

与:比较:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
    {
        for (auto j = 0; j < a.h(); ++j)
        {
            c(i, j) = a(i, j) + b(i, j);
        }
    }

    return c;
}

第一个代码简明扼要;第二个代码是膨胀的。

是的,通过在前一行放置左括号,可以在某种程度上减轻 。但是,仍然的可读性低于没有任何大括号的代码。

简而言之:不要编写占用屏幕空间的不必要代码。

答案 4 :(得分:39)

我正在研究的代码库中散布着代码,这些代码是由对病毒的病态厌恶的人而存在的,对于后来出现的人来说,它确实可以对可维护性产生影响。

我遇到的最常见的问题是:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
    this_looks_like_a_then-statement_but_isn't;

因此,当我出现并希望添加一个声明时,如果我不小心,我可以很容易地结束这个:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
{
    this_looks_like_a_then-statement_but_isn't;
    i_want_this_to_be_a_then-statement_but_it's_not;
}

鉴于添加大括号需要大约1秒,并且可以至少节省几分钟的调试时间,为什么你会使用简化模糊选项?对我来说似乎是虚假的经济。

答案 5 :(得分:19)

我的2c:

  

使用缩进

显然

  

永远不要依赖运算符优先级 - 始终使用括号

我不会使用“never and”always“这两个词,但总的来说,我认为这条规则很有用。在某些语言中(Lisp,Smalltalk),这不是问题。

  

始终使用{}块 - 即使是单行

我从来没有这样做,从来没有遇到任何问题,但我可以看到它对学生有什么好处,尤其是。如果他们之前研究过Python。

  

比较左侧的Const对象

尤达的条件?不谢谢。它伤害了可读性。只需在编译代码时使用最大警告级别。

  

对于&gt; = 0

的变量使用无符号

行。有趣的是,我听说Stroustrup不同意。

  

删除后将指针设置为NULL - 双删除保护

糟糕的建议!永远不要有指向已删除或不存在的对象的指针。

答案 6 :(得分:17)

它更直观,更容易理解。它使意图明确。

当新用户在添加新代码语句时可能在不知不觉中错过{}时,它确保代码不会中断。

答案 7 :(得分:13)

为了增加上面非常明智的建议,我在重构一些关键的代码时遇到的一个例子如下:我正在改变一个非常大的代码库来从一个API转换到另一个API。第一个API调用了如下设置公司ID:

setCompIds( const std::string& compId, const std::string& compSubId );

而替换需要两个电话:

setCompId( const std::string& compId );
setCompSubId( const std::string& compSubId );

我开始使用非常成功的正则表达式来改变它。我们还通过astyle传递了代码,这使得它更具可读性。然后,在审查过程的一部分,我发现在一些有条件的情况下,它正在改变这一点:

if ( condition )
   setCompIds( compId, compSubId );

对此:

if ( condition )
   setCompId( compId );
setCompSubId( compSubId );

显然不是什么要求。我不得不回到开头再做一次,将替换完全视为一个块,然后手动修改最终看起来很傻的东西(至少它不会是错误的。)

我注意到astyle现在有--add-brackets选项,允许你在没有括号的地方添加括号,如果你发现自己处于和我相同的位置,我强烈推荐这个

答案 8 :(得分:8)

我在任何地方都使用{},除了少数显而易见的情况。单行是其中一种情况:

if(condition) return; // OK

if(condition) // 
   return;    // and this is not a one-liner 

在返回之前添加某些方法可能会对您造成伤害。缩进表示当满足条件时返回正在执行,但它将始终返回。

使用statment

的C#中的其他示例
using (D d = new D())  // OK
using (C c = new C(d))
{
    c.UseLimitedResource();
}

相当于

using (D d = new D())
{
    using (C c = new C(d))
    {
        c.UseLimitedResource();
    }
}

答案 9 :(得分:8)

我能想到的最相关的例子:

if(someCondition)
   if(someOtherCondition)
      DoSomething();
else
   DoSomethingElse();

if与哪个else配对?缩进意味着外部if获得else,但实际上并不是编译器将如何看到它; 内部 if将获得else,而外部if则不会。你必须知道(或者在调试模式下看到它的行为)通过检查来确定为什么这段代码可能会失败你的期望。如果你了解Python,它会变得更加混乱;在这种情况下,您知道缩进定义了代码块,因此您希望它根据缩进进行评估。然而,C#并没有对空白进行翻转。

现在,我说,我并不特别同意这个“总是使用括号”的规则。它使代码非常垂直嘈杂,降低了快速读取代码的能力。如果声明是:

if(someCondition)
   DoSomething();

...那么它应该像这样写。声明“总是使用括号”听起来像“总是用括号括起数学运算”。这会将非常简单的陈述a * b + c / d转变为((a * b) + (c / d)),从而引入错过近亲(许多编码员的祸根)的可能性,以及为什么?操作顺序众所周知且执行得很好,因此括号是多余的。您只能使用括号来强制执行与通常应用的操作不同的操作顺序:例如a * (b+c) / d。块状括号类似;使用它们来定义你想要做的事情,如果它与默认值不同,并且不是“明显的”(主观的,但通常很常识)。

答案 10 :(得分:5)

因为当你有两个没有{}的陈述时,很容易错过一个问题。我们假设代码看起来像这样。

int error = 0;
enum hash_type hash = SHA256;
struct hash_value *hash_result = hash_allocate();

if ((err = prepare_hash(hash, &hash_result))) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &client_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &server_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &exchange_params)) != 0)
    goto fail;
    goto fail;
if ((err = hash_finish(hash)) != 0)
    goto fail;

error = do_important_stuff_with(hash);

fail:
hash_free(hash);
return error;

看起来很好。它的问题很容易被遗漏,特别是当包含代码的函数更大时。问题是goto fail是无条件运行的。你很容易想象这是多么令人沮丧(让你问为什么上一个hash_update总是失败,毕竟在hash_update函数中一切都很好。)

但是,这并不意味着我要在任何地方添加{}(在我看来,看到{}到处都很烦人)。虽然它可能导致问题,但它从来没有对我自己的项目做过,因为我的个人编码风格禁止条件没有{}当它们不在同一条线上时(是的,我同意我的编码风格是非常规的,但我喜欢它,我在贡献其他项目时使用项目的代码风格)。这使得以下代码正常。

if (something) goto fail;

但不是下一个。

if (something)
    goto fail;

答案 11 :(得分:5)

通过答案,没有人明确说明我习惯的那种练习,讲述你的代码的故事:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

变为:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0) j++;
}

j++放在与相同的行上的if应该向其他人发出信号,“我只希望此块增加j。如果线条尽可能简单,那么coursethis是值得的,因为在peri中提到一个断点并不会非常有用。

事实上,我刚刚遇到了部分Twitter Storm API,它在java中有这种'代码',这里是执行代码的relvant片段,在page 43 of this slideshow上:

...
Integer Count = counts.get(word);
if (Count=null) count=0;
count++
...

for循环块有两个内容,所以我不会内联该代码。即从不

int j = 0;
for (int i = 0 ; i < 100 ; ++i) if (i % 2 == 0) j++;

这很可怕,我甚至不知道它是否有效(按预期); 不要这样做。新的线条和大括号有助于区分单独但相关的代码片段,就像散文中的逗号或分号一样。上面的块是一个很长的句子,有一些条款和一些其他语句从不打破或暂停以区分不同的部分。

如果你真的想要给其他人发电报,那么这是一个单行工作,使用三元运算符或?:形式:

for (int i = 0 ; i < 100 ; ++i) (i%2 ? 0 : >0) j++;

但这是代码高尔夫,我认为不是很好的练习(我不清楚我是否应该将j + +放在:的一边)。 NB 我之前没有在C ++中运行三元运算符,我不知道这是否有效,但确实存在

简而言之:

想象一下您的读者(即维护代码的人)如何解释您的故事(代码)。让它们尽可能清楚。如果你知道新手编码器/学生正在维护这个,甚至可能留下尽可能多的{},这样他们就不会感到困惑。

答案 12 :(得分:4)

我喜欢Luchian接受的答案,事实上我学到了他的正确方法,所以我总是使用大括号,即使对于单行块也是如此。但是,就像你在你的例子中一样,我个人在编写过滤器时会例外。这样:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}
看起来很杂乱。它将for循环和if语句分成单独的动作,当你的意图真的是单个动作时:计算所有可被2整除的整数。用更具表现力的语言,这可以写成:

j = [1..100].filter(_%2 == 0).Count

在缺少闭包的语言中,过滤器不能在单个语句中表示,但必须是for循环,后跟if语句。但是,它仍然是程序员心中的一个动作,我相信这应该反映在代码中,如下所示:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
  if (i % 2 == 0)
{
    j++;
}

答案 13 :(得分:4)

有助于防止上述错误的一个选项是在不使用大括号时内联您想要发生的内容。当您尝试修改代码时,它会更难以注意到错误。

if (condition) doSomething();
else doSomethingElse();

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong

答案 14 :(得分:4)

wrt 6:它更安全,因为删除空指针是一个无操作。因此,如果您偶然两次经历该路径,则不会导致内存损坏,从而释放可用内存或已分配给其他内存的内存。

这是静态文件范围对象和单例的大部分问题,这些对象和单例的生命周期不是很明显,并且在被破坏后会被重新创建。

在大多数情况下,您可以使用auto_ptrs

来避免这种情况

答案 15 :(得分:4)

通过明确定义循环和条件块的范围,使代码更具可读性。它还可以避免意外错误。

答案 16 :(得分:3)

如果您是编译器,它没有任何区别。两者都是一样的。

但对于程序员来说,第一个更清晰,易于阅读且不易出错。

答案 17 :(得分:3)

添加花括号的另一个例子。 一旦我在搜索错误并找到了这样的代码:

void SomeSimpleEventHandler()
{
    SomeStatementAtTheBeginningNumber1;
    if (conditionX) SomeRegularStatement;
    SomeStatementAtTheBeginningNumber2;
    SomeStatementAtTheBeginningNumber3;
    if (!SomeConditionIsMet()) return;
    OtherwiseSomeAdditionalStatement1;
    OtherwiseSomeAdditionalStatement2;
    OtherwiseSomeAdditionalStatement3;
}

如果您逐行阅读该方法,您会注意到方法中存在一个条件,如果不是这样,则返回该条件。但实际上它看起来像其他100个简单的事件处理程序,它们根据某些条件设置了一些变量。有一天Fast Coder进来并在方法结束时添加了额外的变量设置语句:

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

因此,在SomeConditionIsMet()时执行SetAnotherVariableUnconditionnaly,但快速的人没有注意到它,因为所有行的大小几乎相似,即使返回条件是垂直缩进的,也不是那么明显。 / p>

如果条件返回的格式如下:

if (!SomeConditionIsMet())
{
    return;
}

它非常明显,快速编码器会一目了然。

答案 18 :(得分:2)

我认为第一个要清楚,然后是第二个。它给出了关闭指令的感觉,代码变得复杂时代码很少{...}有很大帮助,即使它是endifbegin...end

//first
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}


//second
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

答案 19 :(得分:1)

最好在完成后将指针设置为NULL。

以下是一个例子:

A类执行以下操作:

  1. 分配一块内存
  2. 然后一段时间后,它会删除此内存块,但不会将指针设置为NULL
  3. B类执行以下操作

    1. 分配内存(在这种情况下,它恰好被赋予了由A类删除的相同内存块。)
    2. 此时,A类和B类都有指向同一个内存块的指针,就A类而言,这个内存块不存在,因为它已经完成了。

      考虑以下问题:

      如果A类中存在逻辑错误导致写入现在属于B类的内存,该怎么办?

      在这个特定的实例中,你不会得到错误的访问异常错误,因为内存地址是合法的,A类现在都在有效地破坏B类数据。

      如果遇到意外的值,B类最终可能会崩溃,当它崩溃时,很有可能,当问题出现在A类时,你会花很长时间在B类中找到这个bug。

      如果您已将已删除的内存指针设置为NULL,那么只要A类中的任何逻辑错误都尝试写入NULL指针,就会出现异常错误。

      如果你担心第二次指针为NULL时双重删除的逻辑错误,那么为此添加断言。

      另外:如果你要投票,请解释。

答案 20 :(得分:1)

我必须承认,并不总是使用{}作为单行,但这是一个很好的做法。

  • 让我们说你编写一个没有括号的代码,如下所示:

    for(int i = 0; i&lt; 100; ++ i) for(int j = 0; j <100; ++ j) DoSingleStuff();

过了一段时间,你想在j循环添加一些其他内容,你只需通过对齐来做,然后忘记添加括号。

  • 内存处理速度更快。让我们说你有很大的范围并在里面创建大数组(没有new所以它们在堆栈中)。离开范围后,这些数组正在从内存中删除。但是你有可能在一个地方使用那个数组,它会在堆栈中存在一段时间并成为某种垃圾。由于堆栈具有有限且非常小的尺寸,因此可能超过堆栈大小。因此,在某些情况下,最好编写{}来防止这种情况发生。 注意这不适用于单行,但适用于以下情况:

    if(...) {     // SomeStuff ...     {//我们没有if,while等。         // SomeOtherStuff     }     // SomeMoreStuff }

  • 使用它的第三种方式与第二种类似。它只是为了使堆栈更清洁,而是打开一些功能。如果你在长函数中使用mutex,通常最好在访问数据之前和完成读/写之后锁定和解锁。 注意如果您拥有自己的classstruct constructordestructor以锁定内存,则会使用这种方法。

    < / LI>
  • 更重要的是:

    if(...)    如果(...)       SomeStuff(); 其他    SomeOtherStuff(); //转到第二个if,但是alligment显示它是第一个...

All In All,我不能说,总是将{}用于单行的最佳方式是什么,但这样做并不是坏事。

重要编辑如果您为一行编写编译代码括号什么都不做,但如果您的代码被解释,它会非常轻微地减慢代码速度。很轻微。

答案 21 :(得分:1)

始终拥有花括号是非常简单而强大的规则。但是代码可能看起来像 当有很多大括号时不够优雅。如果规则允许省略花括号,则应该有更详细的样式规则和更复杂的工具。否则,它可能很容易导致混乱和混乱(不优雅)的代码。因此,看起来单独的风格规则与其他风格指南和使用的工具分开可能没有结果。我将带来一些关于规则#3的重要细节,这些细节在其他答案中甚至没有提到过。

第一个有趣的细节是,该规则的大多数支持者同意在else的情况下违反该规则。换句话说,他们不要求审查这样的代码:

// pedantic rule #3
if ( command == Eat )
{
    eat();
}
else
{
    if ( command == Sleep )
    {
        sleep();
    }
    else
    {
        if ( command == Drink )
        {
            drink();
        }
        else
        {
            complain_about_unknown_command();
        }
    }
}

相反,如果他们看到它们,他们甚至可能会建议像这样写:

// not fully conforming to rule #3
if ( command == Eat )
{
    eat();
}
else if ( command == Sleep )
{
    sleep();
}
else if ( command == Drink )
{
    drink();
}
else
{
   complain_about_unknown_command();
}

这在技术上违反了该规则,因为elseif之间没有大括号。规则的这种二元性表面何时尝试使用无意识的工具自动将其应用于代码库。实际上,为什么要争论,只需让工具自动应用样式。

第二个细节(通常也被该规则的支持者所遗忘)是,可能发生的错误绝不仅仅是因为违反了规则#3。实际上那些也几乎总是涉及违反规则#1(没有人反对)。再次从自动工具的角度来看,当违反规则#1时,立即抱怨的工具并不难,因此可以及时发现大多数错误。

第三个细节(通常被该规则的反对者所遗忘)是由单个分号表示的空语句的混乱性质。大多数具有一定经验的开发人员迟早会因单独错误的分号或使用单独分号编写的空语句而感到困惑。两个花括号而不是单个分号在视觉上更容易被发现。

答案 22 :(得分:1)

编写控制语句有很多种可能的方法;它们的某些组合可以共存而不会损害易读性,但是其他组合会引起麻烦。风格

for x in range(9,100):
    initial_file = 'C:\Users\Alex\Desktop\test\X_Y.txt'
    dest_file = 'C:\Users\Alex\Desktop\test\file_' + str(x+1) + '_100.idf'
    shutil.copy2(initial_file, dest_file)

将与其他一些编写控制语句的方式舒适地共存,但与其他方式不太一样。如果多行控制语句写为:

if (condition)
  statement;

然后在视觉上可以看出哪些if (condition) { statement; statement; } 语句控制一行,哪些语句控制多行。但是,如果多行if语句写为:

if

然后,某人尝试扩展单个语句if (condition) { statement; statement; } 构造而不添加必要的括号的可能性可能要高得多。

如果代码库大量使用表单,那么单个语句在下一行if语句也可能会出现问题

if

我自己的偏好是,除了在有许多具有类似控制块的if (condition) statement; 语句的情况下,将语句放在自己的行上通常会增强易读性,例如

if

在这种情况下,我通常会在if (x1 > xmax) x1 = xmax; if (x1 < xmin) x1 = xmin; if (x2 > xmax) x2 = xmax; if (x2 < xmin) x2 = xmin; etc. if语句组之前和后面跟一个空行,以便在视觉上将它们与其他代码分开。在同一个缩进处有一系列以if开头的陈述将提供清晰的视觉指示,表明存在异常现象。