C 编程 - while 循环中的逗号运算符

C Programming - comma operator within while loop

程序 1:

#include<stdio.h>
 int main()
 {
     int i=0;
     while(i<=8,i++);
     printf("%d",i);
     return 0;
  }

程序 2:

#include<stdio.h>
 int main()
{
  int i=0;
  while(i++,i<=8);
  printf("%d",i);
  return 0;
}

Prog 1的输出是1,Prog 2的输出是9。

谁能解释一下这是怎么回事。这两个代码有什么不同?

逗号运算符依次计算它的两个参数,丢弃除最后一个以外的结果。最后计算的表达式决定了整个表达式的结果。

i<=8,i++ - 这里表达式的值是i++的值,这是i递增前的值。它为 0,因此循环立即终止。

i++,i<=8 - 这里表达式的值是 i<=8 的值,只有当 i 递增到 9 时才为 0。

个人意见:我认为第二种形式虽然有点类似于 for 循环,但对于代码的 reader 而言不如实际的 for 循环清晰。

表达式分隔符,强制从左到右求值,也是排序点.

程序 1:考虑 i <= 8, i++i <= 8 被评估并丢弃,然后 i++ 被评估。整个表达式的值为i,没有增加。由于 i 最初是 0,因此 while 循环在第一次迭代时终止。输出将是 i 的单个递增值,即 1.

Prog 2:评估 i++ 并丢弃结果,然后使用 inew 值评估 i <= 8,因为 , 是一个 序列点 。因此 while 循环一直运行到 i <= 8 不再是 true 并增加了 i 的值。输出将是 9.

1 while ( condition )
2    statement;
3 more_code();

在上面的代码片段中,只要conditiontrue就可以重复执行statement。在 while 循环的每次迭代中,condition 被评估为 truefalse。如果它是 false,则 while 循环结束并继续执行超出它的范围(在这种情况下,第 4 行 more_code().

我们通常习惯用大括号{}将要循环执行的部分代码括起来,但这不是强制性的。如果我们不这样做,循环代码将由单个语句组成,即紧跟在 while 部分之后的语句。

实际上可以说更常见的情况是,我们将 while 与大括号括起来 代码块 可以解释为提供此代码块代替单个语句,大括号提供块应该被处理的信息(通过编译器分析它与前后代码的关系)as if 这是一个单一的声明。

但是,由于提供单个语句而不是通常的代码块是完全有效的,因此有必要了解存在一个有效的空语句。我们通过键入一个分号得到一个空语句,而没有在它前面加上任何导致任何事情的代码。所以以下是完全有效的:

1 code;
2 ; // empty statement
3 ; // another empty statement

或者实际上是这样的:

1 code;; // a "code" statement followed by empty statement in the same line

while( condition )部分没有以分号结束,所以如果它应该控制一些实际代码(除了condition),它后面不应该跟分号。如果它后面紧跟一个分号,则该分号将构成(并被编译器如此解释)一个空语句,因此循环代码将为空。如果这是无意的,那么我们想要循环的代码,无论是代码块还是语句,都不会被循环,而是在(和如果)循环结束后执行一次。

1 int a = 0;
2 while ( a < 3 ) ; // Next line is not part of loop - only the empty statement this semicolon creates is. This loop is infinite, or in other words it will never end.
3    a++; // This won't be executed even once.
4 printf("This never happens."); 

(值得一提的是,在 C 中,行仅对我们人类很重要。如果行和缩进代表了程序员的意图,那么当他未能编写出如下代码时,行和缩进可能会产生误导他想要它。)

因此,问题的两个片段中发生了什么,我们得到 condition 连续评估,直到它产生 false。要了解发生了什么,我们需要检查逗号运算符的工作方式。

(注意,虽然逗号作为字符在 C 语言的不同地方可以使用完全不同的含义——我可以想到函数声明、定义和调用——在这种情况下,逗号字符是条件的一部分,因此它充当 运算符 - 类似于 +% 运算符。)

expression1 , expression2

逗号运算符导致 expression1 首先被评估,然后 expression2,returns expression2.

的值

在每次评估条件时,我们将评估两个表达式(在本例中都是操作数,i++i<=8),然后将正确的值视为逗号的结果操作数本身,因此作为我们条件的价值。因此,只要正确的操作数解析为 true.

,循环就会一直重复

虽然通常我们使用条件来控制循环的执行,但在这种情况下,condition 通常可能会产生“副作用”(有意或无意)。在我们的例子中,变量 i 受到每个 condition 评估的影响:它增加了一个。

我们的示例仅在 condition 的操作数顺序上有所不同,因此请注意真正控制循环执行的正确操作数。

我们先来看第二个例子。在这种情况下,我们有条件 i++, i<=8。这意味着在每次评估时我们首先增加 i,然后检查它是否小于或等于 8。因此在第一次评估条件时我们将 i 从 0 增加到 1 并得出结论 1<=8 ,所以循环继续。当 i 变为 9 时,如此构造的循环将中断,即。在第 9 次迭代时。

现在第一个例子,条件是i<=8, ++i。由于比较没有副作用,也就是说我们可以按任何顺序执行任意数量的比较,如果这是我们唯一做的事情,也就是说如果我们没有以依赖于比较结果的方式或顺序执行任何其他操作,这些比较绝对无济于事。正如在我们的例子中,我们计算 i<=8,它计算为 truefalse,但我们不使用这个结果,只是继续计算正确的操作数。所以左操作数绝对无关紧要。另一方面,右操作数有副作用,它的值成为整个条件的值。在每次循环迭代之前,我们检查 i++ 是否计算为 truefalse.

i++ 是 post-incrementation 的一元运算符。 returns i then 的值增加一(i++ 和 ++i 之间的区别很微妙,但在这种情况下很重要)。那么会发生什么是我们首先检查 itrue 还是 false,然后 i 增加 1。

C 中没有 boolean 类型。如果整数具有 non-zero 值,则整数被认为是 true

因此,在 i++ 的第一次评估中,我们得到 0,即 false。这意味着循环甚至没有一次迭代就被打破了。但是,它不会中断 i++ 的计算,这会导致 i 在我们完成循环并继续执行之前增加 1。所以一旦我们完成了 while 循环,i 已经是 1.

如果我们想在理解上非常精确,我们获取评估整个条件的结果的部分按时间顺序发生,我们完成执行涉及的任何代码之后这个评价。所以我们首先记住i在我们到达i++部分时为0,然后我们将i加一,然后我们完成执行condition,所以我们为决定我们是否应该进行另一次(在这种情况下首先)迭代或跳出循环部分并继续前进的代码提供值 0。这就是为什么即使循环将结束的事实已经确定,条件内的一切都会实际发生的确切原因:它已确定,但直到 condition 完成执行后才进行检查和操作。