逗号不排除for循环;它是逗号运算符。
x = (a, b);
首先执行a,然后执行b,然后将x设置为b的值。
for语法为:
for (init; condition; increment)
...
这是有点(忽略continue和break现在),相当于:
init;
while (condition) {
...
increment;
}
因此,您的for循环示例等同于(再次忽略continue和break)
p=0;
while (p+=(a&1)*b,a!=1) {
...
a>>=1,b<<=1;
}
哪个看起来像(再次忽略continue和break):
p=0;
while (true) {
p+=(a&1)*b;
if (a == 1) break;
...
a>>=1;
b<<=1;
}
for循环的两个额外细节,不在上面的while循环的简化转换中:
如果省略的条件下,它总是true(导致无限循环,除非break,goto或别的东西断裂的循环)。
A的continue行为就像是在增量之前转到标签,continue而while循环中的跳过将跳过增量。
另外,还有一个有关逗号运算符的重要细节:它是一个序列点,例如&&和||(这就是为什么我可以将其拆分为单独的语句并保持其含义完整的原因)。
C99的变化
C99标准引入了一些在此解释中未提及的细微差别(对于C89 / C90非常好)。
首先,所有循环本身就是块。有效,
for (...) { ... }
本身用大括号包裹
{
for (...) { ... }
}
标准说:
ISO / IEC 9899:1999§6.8.5迭代语句
¶5迭代语句是一个块,其作用域是其封闭块作用域的严格子集。循环主体还是一个块,其作用域是迭代语句作用域的严格子集。
在基本原理中也用额外的花括号进行了描述。
其次,initC99中的部分可以是一个(单个)声明,如
for (int i = 0; i < sizeof(something); i++) { ... }
现在,“环绕循环的块”变成了自己。它解释了为什么i无法在循环外部访问变量。您可以声明多个变量,但它们都必须具有相同的类型:
for (int i = 0, j = sizeof(something); i < j; i++, j--) { ... }
标准说:
ISO / IEC 9899:1999§6.8.5.3for声明
该声明
for ( clause-1 ; expression-2 ; expression-3 ) statement
其行为如下:表达式expression-2是控制表达式,该表达式在每次执行循环主体之前进行评估。每次执行循环体后,表达式expression-3都将被评估为无效表达式。如果子句1是一个声明,则它声明的任何变量的范围是声明的其余部分和整个循环,包括其他两个表达式;在第一次对控制表达式求值之前按执行顺序达到它。如果子句1是表达式,则在对控制表达式进行第一次求值之前,将其作为void表达式求值。133)
子句1和表达式3都可以省略。省略的expression-2替换为非零常量。
133)因此,第1节指定了循环的初始化,可能会声明一个或多个变量供循环使用;控制表达式expression-2指定在每次迭代之前进行的求值,以便继续执行循环,直到表达式比较等于0为止;而expression-3指定在每次迭代之后执行的操作(例如递增)。