我来自高级OOP语言C#和Java,最近开始在C中挠头。我觉得C和JS一样有点奇怪。所以我想澄清一下:
下面给出了错误,这似乎很直观,因为它看起来像是不正确的语法,即使在OOP语言中也是如此
int i=0,1,2;
/*
Error : expected identifier or ‘(’ before numeric constant
int i = 0, 1, 2;
^
*/
然而,下面的工作原理令人惊讶:
int i;
i = 0,1,2; //works
为什么会有这种行为?它们对保持这样的行为有什么意义吗?还是只是一些解析技术细节?
i = 0,1,2;
这是任务,相当于:
(i = 0), 1, 2;
逗号运算符(优先级最低)从左到右计算所有操作数,首先计算赋值i = 0
,然后计算表达式1
和2
,并丢弃结果。
的第二个例子
int i=0,1,2;
是初始化。将其与合法初始化int i = 0, j = 0;
进行比较。
如果你使用,它会起作用
int i=(0,1,2);
这实际上是一个棘手的问题,因为它依赖于复杂的C语法的细节。理解它的最佳来源是标准草案,我们可以使用Annex A
语言语法摘要作为参考。
基本思想是:
int i=0,1,2;
是一个声明和:
i = 0,1,2;
是一个表达式。
在表达式中,我们可以使用逗号运算符来评估左手边(通常用于副作用),丢弃结果,然后评估右手边等。
在声明中,逗号是语法分隔符,而不是逗号运算符。,
分隔声明符,由于1
和2
在声明上下文中不是声明符,这是不正确的语法:
int i=0,1,2;
^^^^
C99标准的相关语法如下:
init-declarator-list:
init-declarator
init-declarator-list , init-declarator <--- here comma is just a seperator
init-declarator:
declarator
declarator = initializer
因此,在这种情况下, 初始值设定项可以是赋值表达式,这一点毫无价值,但该表达式并没有为我们提供一个通向空逗号运算符的路径,尽管我们最终可能会在 对于表达式, 逗号运算符的描述如下: 逗号运算符的左操作数计算为空表示在其评估之后有一个序列点。然后计算右操作数;结果有其类型和值。[…] 注意逗号运算符的优先级最低,请使用以下表达式: 相当于: 因此CCD_ 14将得到CCD_。,
将init声明符分隔开,它们可以是声明符或宣告符=初始值设定项1
和2
都不是申明符()
中使用逗号运算符(通过主表达式),但这看起来不像分隔符。6.5.17
节中的相关语法为:expression:
assignment-expression
expression , assignment-expression
i = 0,1,2;
(i = 0),1,2;
1.
int i, j;
i = 3,0,1,2;
printf("%dn", i); => prints 3
2.
i = 3,j =7;
printf("%d, %dn", i, j); => prints 3 and 7
i = 3,0,1,2;
分配3 to i
,然后执行0, 1 and 2
。检查我提到的第二个例子。
此外,尝试i=3;0;1;2;
这不会报告任何错误。它将只执行(i=3), (0), (1) and (2)
。