【问题标题】:In C/C++ why does the do while(expression); need a semi colon?在 C/C++ 中为什么 do while(expression);需要半冒号吗?
【发布时间】:2009-06-02 22:31:17
【问题描述】:

我的猜测是它只是让解析更容易,但我不明白为什么。

那么这有什么...

do
{
  some stuff
}
while(test);

more stuff

这比……好

do
{
  some stuff
}
while(test)

more stuff

【问题讨论】:

    标签: c++ c language-design


    【解决方案1】:

    因为你要结束陈述。语句以块(由花括号分隔)或分号结束。 “do this while this”是一条语句,不能以块结尾(因为它以“while”结尾),所以它需要一个分号,就像任何其他语句一样。

    【讨论】:

    • 嗯,这个问题有一些合法性。 for(;;) {做某事;除了与包含的语句一起使用的分号之外,实际上不以任何分号结尾。
    • @Matthias: 但它以花括号结尾。
    • 之所以必须是“声明”,是因为计算机正在将您的代码组合成一个程序..一致性不是为了程序员
    • 如果看起来随意,请尝试在没有它的情况下编写语法。由于语句可以嵌套,因此您需要定义分隔符。在 C/C++ 中,这是 ';'。
    • 接受的答案只是做出了不同的断言,您直观地认为它是“正确的”和“明确的例子”,而实际上它是绝对不正确的。您认为“如果语法不同”会出现的问题实际上不会出现。
    【解决方案2】:

    如果你看一下 C++ 语法,你会发现迭代语句被定义为

    while ( 条件 ) 语句

    for ( for-init-statement 条件-opt ; 表达式-opt ) 声明

    语句 while ( 表达式 ) ;

    请注意,只有do-while 语句的末尾有;。所以,问题是为什么do-while 与其他的如此不同以至于它需要额外的;

    让我们仔细看看:for 和普通的while 都以 语句 结尾。但是do-while 以包含在() 中的控制表达式 结束。封闭() 的存在已经允许编译器明确地找到控制表达式的结尾:外部封闭) 指定表达式结束的位置,因此,整个do-while 语句结束的位置。也就是说,终止;确实是多余的。

    但是,在实践中这意味着,例如,下面的代码

    do
    {
      /* whatever */
    } while (i + 2) * j > 0;
    

    while valid 从语法上看,确实会被解析为

    do
    {
      /* whatever */
    } while (i + 2)
    
    *j > 0;
    

    这在形式上是合理的,但实际上并不直观。我猜出于这样的原因,决定在do-while 语句中添加一个更明确的终止符——一个分号。当然,根据@Joe White 的回答,还需要考虑简单明了的一致性:C 中的所有普通(非复合)语句都以 ; 结尾。

    【讨论】:

    • 可以看到问题没有被编辑,有编辑的时候显示编辑的数量。这个问题似乎很简单,我希望它意味着我的意图。接受的答案似乎优于您的答案,因为它表明没有分号,语法的有效用法会变得模棱两可。在您的示例中,它只是让用户感到困惑。
    • @justinhj:不,绝对不正确。接受的答案令人困惑,因为它暗示了一些“不同的行为”,但未能解释这些行为是什么。可以预料的是,正如您自己很容易看到的那样,当他假设没有分号要求的内部while 语句将与外部do 错误关联时,接受答案的评论者之一实际上感到困惑。这根本不是真的。语法经过专门设计,不会让这种情况发生,无论是否使用分号。
    • 我希望接受答案的作者能够澄清,他暗示了哪些“不同的行为”......没有那个接受的答案根本不是答案。
    • +1 是唯一正确的答案,如果不需要分号会发生“坏”的真实例子。
    • @Tony:AndreyT 的回答根本没有表示模棱两可的意思——正如它所说,因为需要括号,所以解析不是模棱两可的——它只是可能不直观。
    【解决方案3】:

    这是因为 while 语句在 do-while 循环中是有效的。

    如果不需要分号,请考虑不同的行为:

    int x = 10;
    int y = 10;
    
    do 
      while(x > 0)
        x--;
    while(x = y--);
    

    【讨论】:

    • do 和 while 之间没有指令这一事实足以让编译器找到 while "end of do" 和 while "new loop" 之间的区别。你的例子很有趣,但我认为它不能解释为什么在 do's while 之后有一个分号。
    • onebyone:不是真的。 do while(...); 不合法。一个空的 do-while 循环写成:do ; while(...);do {} while(...); 否则它不会编译。
    • -1。这个例子似乎暗示如果没有尾随; 要求,代码会以某种方式被误解。实际上,语言语法(即使是当前形式)不允许对上述代码进行任何所谓的误解,即使删除了结尾的 ; 要求。 Benoît 是对的:该示例没有解释与该问题相关的任何内容。这个答案是不正确的。我允许 Don 暗示我遗漏的东西的可能性,但在他澄清他的意思之前,这是一个可靠的 -1。
    • 这个答案是错误的 - do while (x > 0) x--; 不能被误解为一个空循环,其控制表达式为 x > 0,后跟 x--; 语句。这是因为空循环必须写成do ; while (expr)do {} while (expr)——循环体必须是一个语句。
    • @Steve:在 C++ 和 C 中,do while (x) 是不合法的:您必须使用 do ; while (x) 或执行 { } while (x)`。 Benoît 和 AndreyT 是正确的。
    【解决方案4】:

    虽然我不知道答案,但一致性似乎是最好的论据。 C/C++ 中的每个语句组都由

    终止
    1. 分号
    2. 大括号

    为什么要创建一个两者都不做的构造?

    【讨论】:

    • 那么,为什么我不能这样做:int testFunc(int x) return x+1;
    • @Rocketmagnet,你不能允许所有语句(包括空语句),因为 "void f() ;" (以“空语句”为主体的函数定义)与“void f();”没有区别(仅限函数声明)。两者看起来都一样。要求复合语句是一件好事。无论如何,函数定义不是语句。
    【解决方案5】:

    流控语句一致性

    考虑一致性...

    if (expr) statement;
    do statement; while (expr);
    for (expr; expr; expr) statement;
    while (expr) statement;
    

    ...所有这些流控制结构都以分号结尾。

    但是,我们可以注意到在块语句形式中,只有 do while 是用分号分隔的:

    if (expr) { ... }
    do { ... } while (expr);
    for (expr; expr; expr) { }
    while (expr) { }
    

    所以,我们有';'或 '}',但绝不是“裸露的”')'。

    语句分隔符的一致性

    我们至少可以说每个语句都必须由;} 分隔,并且在视觉上有助于我们区分语句。

    如果不需要分号,请考虑:

    do statement1; while (expr1) statement2; do ; while (expr2) statement3; while (expr3) statement4;
    

    很难从视觉上将其解决为不同的语句:

    do statement1; while (expr1)
    statement2;
    do ; while (expr2)
    statement3;
    while (expr3) statement4;
    

    相比之下,在while 条件告诉您向后寻找do 并且下一条语句与while 无关之后,以下情况更容易解决为;

    do statement1; while (expr1); statement2; do ; while (expr2); statement3; while (expr3) statement4;
    

    考虑到人们缩进他们的代码以使流程易于理解,这是否重要?是的,因为:

    • 人们有时会犯错误(或者在修改代码时暂时出现错误),如果它在视觉上很突出,这意味着它会更容易修复,并且
    • 宏替换可以将大量语句放在一行中,我们有时需要在排除故障或进行 QA 时直观地验证预处理器输出。

    对预处理器使用的影响

    同样值得注意的是著名的预处理器 do-while 习语:

    #define F(X) do { fn(X); } while (false)
    

    这可以替换为:

    if (expr)
        F(x);
    else
        x = 10;
    

    ...产量...

    if (expr)
        do ( fn(x); } while (false);
    else
        x = 10;
    

    如果分号 不是 do while 语句的一部分,那么 if 语句将被解释为:

    if (expr)
        do-while-statement
    ; // empty statement
    else
        x = 10;
    

    ...而且,因为if 之后有两个语句,所以它被认为是完整的,这使得else 语句不匹配。

    【讨论】:

      【解决方案6】:

      C 以分号结尾(而 Pascal 以分号分隔)。将分号放在那里会不一致。

      坦率地说,我讨厌在 do 循环中重用 while。我认为重复直到会不那么令人困惑。但事实就是如此。

      【讨论】:

        【解决方案7】:

        在 C/C++ 中,空格对结构没有贡献(例如在 python 中)。在 C/C++ 语句中,必须 以分号结束。这是允许的:

        do
        {
          some stuff; more stuff; even more stuff;
        }
        while(test);
        

        【讨论】:

          【解决方案8】:

          我的回答是,当我们没有在do.....while(); 循环的终止中包含分号时,编译器可能会感到困惑。没有这个就不清楚了:

          1. 什么时候结束?
          2. 如果 while 可以在 do 循环之后紧跟一个单独的循环。

          这就是为什么我们在do......while 循环的末尾包含分号,以表明如果条件为假,循环将在此处终止。

          【讨论】:

            猜你喜欢
            • 2020-07-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-02-11
            • 1970-01-01
            • 1970-01-01
            • 2012-05-18
            • 1970-01-01
            相关资源
            最近更新 更多