如果语句中的if语句在语法上是否明确无误?

时间:2016-01-16 20:08:15

标签: c syntax lexical-analysis

我不太了解C,但我理解基础知识,据我所知:

int main() {
  if (1 == 1) printf("Hello World!\n");
  return 0;
}

int main() {
  if (1 == 1) 
    printf("Hello World!\n");
  return 0;
}

int main() {
  if (1 == 1) {
    printf("Hello World!\n");
  }
  return 0;
}

在语法上都是等价的。声明是真的;字符串打印;大括号(显然)是可选的。

有时,特别是在SO上,我看到如下内容:

int main() {
  if (1 == 1)
    printf("one is one\n");
  printf("is this inside the if statement??/who kn0WS\n");
  return 0;
}

通过赋予CodeGolf的权力,我被引导相信C是与空白无关的;词法分析器将标记分解为它们的组成部分,并在字符串外部划出空格。

(我的意思是,每个语句分号的全部原因是解析器可以剥离\n\t文字空间并且仍然知道在哪里每个陈述结束,对吗??)

那么,如果要忽略空格,如何才能明确地解析前一段代码(或者有人可以提出一个更好的例子)?

如果C程序员想要用依赖于空白的Pythonic语法编写,为什么他们会编写C语言,为什么在C语言教学的地方教它可以写出词汇含糊不清(对我,程序员和计算机都有)像这样的陈述?

7 个答案:

答案 0 :(得分:5)

if (1 == 1)
  printf("one is one\n");
printf("is this inside the if statement??/who kn0WS\n");

第二个printf()永远不应该在 if语句中执行

原因是前一行以分号结束,分号表示要执行的 if-block 的结束。

  

(我的意思是,每个语句分号的全部原因   是这样的解析器可以剥离\ n,\ t,文字空格,仍然知道在哪里   每个陈述结束,对吗??)

     

那么如何才能明确地解析前一段代码   (或者也许有人可以提出一个更好的例子,我的意思),   如果要忽略空格?

解析示例

if (1 == 1) // if - - 语句(或块)跟随,跳过所有空格

//没有 {找到 - >单一陈述,扫描到; (外部引用/评论)

遇到

printf("one is one\n"); // ; ,if-block结束

没有大括号,只有一个语句属于 if-block

但是,正如已经说过的那样,使用牙套是个好习惯。如果您以后添加一个语句(例如快速临时printf()),它将始终位于该块内。

特殊情况

int i = 0;
while(i++ < 10);
    printf("%d", i);

此处printf()只会执行一次。在while()的末尾标记;

如果声明为空,最好使用:

while(i++ < 10)
    ;

明确意图(或者,也可以使用空块{})。

答案 1 :(得分:5)

在C中,if语句在真值表达式之后采用完全语句,而不管缩进。通常,为了清楚起见,此语句是缩进的,但C忽略缩进。在任何情况下,您的任何示例都没有任何含糊之处。

在C和许多其他语言中,含糊不清的是“悬而未决”。例如,假设您有一个嵌套的if语句,在第二个语句之后只有一个else。它可以分组为:

if (expr)
    if (expr)
        statement
    else
        statement

或者它可以分组为:

if (expr)
    if (expr)
        statement
else
    statement

这两者之间的唯一区别在于它们是如何缩进的,C忽略了。在这种情况下,通过使用第一解释来解决歧义,即else语句绑定到最近的前if语句。要实现第二种解释,需要花括号:

if (expr) {
    if (expr)
        statement
}
else
    statement

然而,即使在第一种情况下,包括花括号也是一个好主意,即使它们不是必需的:

if (expr) {
    if (expr)
        statement
    else
        statement
}

答案 2 :(得分:3)

tl; dr唯一的模糊之处在于人类阅读的难度。从编译器的角度来看,语法是完全明确的。

if语句后只有两种(可编译和语法上可接受的)可能性:

  1. 大括号,如

    if(x) {
        DoFoo();
    }
    // or
    if(x) { DoFoo(); }
    

    在这种情况下,如果满足条件,{...}中的任何内容都将执行。

  2. 没有大括号,如

    if(x)
        DoFoo();
    // or
    if(x) DoFoo();
    

    在这种情况下,只有符合条件才会执行下一个语句

  3. 你是正确的,C是与空白无关的。因此,省略大括号可能会导致一些棘手的错误。例如,在此代码中,DoBar()将执行是否满足条件:

    if(x)
        DoFoo();
        DoBar();
    

    大括号的使用不一致也很容易导致代码无效。例如,从人的角度来看,这看起来是有效的(一目了然),但事实并非如此:

    if(x)
        DoFoo();
        DoBar();
    else
        DoBaz();
    

    从编译器的角度来看,您发布的所有示例都不明确,但从人的角度来看,无括号版本令人困惑。放弃大括号经常导致难以发现的错误。

答案 3 :(得分:2)

没有大括号,它只是if之后的下一个语句。空白无关紧要

这是一种很好的做法,让生活更轻松,始终使用牙套。良好的缩进也。代码易于阅读,并且在人们在if

之后添加/删除语句时不会导致错误

答案 4 :(得分:2)

可读性是声明中唯一含糊不清的地方:

if(...)

{...}语句后面的第一个语句应该执行的唯一时间是它被评估为TRUE。

大括号,if (1 == 1) { printf("one is one\n"); } printf("is this inside the if statement??/who kn0WS\n"); 有助于消除可读性歧义,

The ID field is required

但语法规则仍然相同。

意见不一致,但我总是选择使用大括号 在编写代码时,不使用它们很好。但是在路上,你只知道有人会出现并在第一个下面添加另一个声明并期望它被执行。

答案 5 :(得分:2)

通常,在带有单个指令的语句或循环中,大括号是可选项;相反,如果您有两个或更多指令,则必须添加它们。 例如:

for(i = 0; i < 2; i++)
   for(j = 0; j < 4; j++)
      If(...)
         printf(..);
      else
         printf(..);

相当于:

for(i = 0; i < 2; i++)
   {
         for(j = 0; j < 4; j++)
         {
             If(...)
             {
                 printf(..);
              }
              else
             {
                 printf(..);
             }
        }
   }

正如您可能注意到的,这与代码缩进有关。就个人而言,如果我只有一条指令,我就不会使用大括号,因为这样可以使你的代码更简洁,更清晰。

答案 6 :(得分:2)

使用大括号的另一个原因是一个简单的拼写错误可能会让你苦苦挣扎:

#include <stdio.h>
int main(void) {
  if (0 == 1)
    printf("zero is one\n"),
  printf("is this inside the if statement?? /who kn0WS\n");
  return 0;
}

仔细看......