【问题标题】:Is it possible to use for loop with misleading syntax?是否可以使用具有误导性语法的 for 循环?
【发布时间】:2020-12-19 12:06:37
【问题描述】:

for循环的语法:

for(initialization;condition;increment/decrement){
statements;
}

为什么下面的代码运行无限次,然后为什么没有语法错误?

int x=10;
for(x++;x++;x++){
printf("\n %d",x);
}

【问题讨论】:

  • 为什么会出现语法错误?
  • @klutt 我猜是因为用作条件的表达式对于用作条件没有意义。
  • @RobertSsupportsMonicaCellio 嗯,这很有意义:for(int i=10; i--; )
  • @klutt 是的,但不幸的是这不是例子。
  • 所有答案都是正确的,将代码跟踪到未定义的行为并将其保留。然而,我会很感激(仔细措辞,因为 UB 仍然是其中的相关部分),讨论在大多数实现中(至少根据我的经验),循环会很长,但不是无限的。从偶数开始,朝着正溢出,然后在负端返回(UB !!!),最后评估为 0 将是我的猜测。考虑到每个循环中第二次出现x++,它仍然会结束......

标签: c loops for-loop operators post-increment


【解决方案1】:

for 循环的 3 个子句是可选的,唯一的要求是它们应该是有效的表达式 - 第一个可以可选地包含变量声明。语法有效。

在第二个子句中,表达式的结果被用作对零的检查。您从 10 开始,因此第一次检查读取值 10,依此类推。它永远不会为零,因此循环不会终止。

除此之外,每个for 子句之后都有一个序列点,因此代码在序列上也是有效的。此代码将不断计数,直到遇到整数溢出,这是未定义的行为。

【讨论】:

    【解决方案2】:

    为什么下面的代码会无限运行...?

    因为使用的条件不会阻止它执行,因为它通常永远不会评估为0

    x 在每次迭代中递增两次,直到达到宏 INT_MAX (limits.h) 中定义的值。在那之后,增加x 调用undefined behavior

    ...那为什么没有语法错误?

    x++ 是一个有效条件,编译器不会检查您设置为条件的表达式是否有意义。它只检查语法错误。所以程序可以编译,运行时无限循环。

    所以回答:

    是否可以使用具有误导性语法的 for 循环?

    答案是:是的。但在这种情况下,它会在某些时候调用上述未定义的行为。

    【讨论】:

    【解决方案3】:

    您使用的“误导性语法”可能很奇怪而且很糟糕,但它仍然有效。这就是您不会收到错误消息的原因。

    循环中的三个子句是通用表达式,但第一个(“初始化”表达式)例外,它允许作为变量定义。

    你得到一个“无限”循环的原因是因为x++ 永远不会是零(这是代表“假”的值)。但是,它会导致未定义的行为,因为当您的增量超出int 的限制时会导致算术溢出。


    如果将for 循环转换为相应的while 循环(所有for 循环都可以转换为while 循环),可能会更容易理解发生了什么。

    for 循环

    for (initialization; condition; increment/decrement)
    {
        statements;
    }
    

    可以翻译成while循环

    initialization;
    while (condition)
    {
        statements;
        increment/decrement;
    }
    

    如果我们现在对有问题的代码做同样的翻译:

    int x = 10;
    for (x++; x++; x++)
    {
        printf("\n %d",x);
    }
    

    变成了

    int x = 10;
    x++;  // initialization
    while (x++)  // condition
    {
        printf("\n %d",x);  // statements
        x++;  // increment/decrement
    }
    

    这可能会让你更清楚发生了什么以及为什么会出现“无限”循环。

    【讨论】:

      【解决方案4】:

      C 标准中以两种方式定义 for 循环

      for ( expressionopt ; expressionopt ; expressionopt ) statement
      for ( declaration expressionopt ; expressionopt ) statement
      

      所以这个for循环

      for ( x++; x++; x++ ){
      

      具有对应于 for 循环的第一个定义的正确形式。

      循环将一直执行,直到第三个表达式 x++ 之后的值 x 等于 0

      如果您使用 unsigned int 类型而不是 int 类型,您将获得正确的有限循环,因为不会出现导致有符号 int 类型未定义行为的溢出。

      unsigned int x=10;
      for(x++;x++;x++){
      printf("\n %d",x);
      }
      

      为了使循环更清晰,让我们在示例中使用变量x 的初始值将等于-3

      int x = -3;
      for ( x++; x++; x++ ){
          printf("\n %d",x);
      }
      

      所以在第一个表达式 x++ 之后 x 将等于 -2,所以当 -2 不等于 0 时,循环体将获得控制权并且 printf 语句将输出 -1 因为 x 是在条件下也增加。

      然后将评估第三个表达式 x++。 x 将等于 0。

      所以现在条件 x++ 将被评估为逻辑假,因为它是 x 在递增之前的值。

      来自 C 标准(6.5.2.4 后缀递增和递减运算符)

      2 后缀++运算符的结果是 操作数。作为副作用,操作数对象的值是 递增(即,将适当类型的值 1 添加到 它)。

      【讨论】:

        猜你喜欢
        • 2015-12-18
        • 1970-01-01
        • 1970-01-01
        • 2012-01-30
        • 2019-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-09
        相关资源
        最近更新 更多