为什么这个逗号的使用在表达式中起作用但在声明中失败?
来自高级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
为什么会这样? 他们保持这种行为或仅仅解析一些技术问题是否有意义?
这实际上是一个棘手的问题,因为它依赖于复杂的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
所以在这种情况下,
分隔init-declarators ,它可以是声明符或声明器=初始化器, 1
和2
都不是声明符 ,因此我们的语法不正确。
初始值设定项可以是赋值表达式,但这个表达式并没有为我们提供一个裸逗号运算符的路径,尽管我们最终可能会在()
( 通过primary-expression )中使用逗号运算符 ,但这不值得。看起来像一个分隔符。
对于表达式, 6.5.17
节中的相关语法是:
expression: assignment-expression expression , assignment-expression
逗号运算符的描述如下:
逗号运算符的左操作数被计算为void表达式; 评估后有一个序列点。 然后评估右操作数; 结果有它的类型和价值。[...]
注意逗号运算符具有以下表达式的最低优先级 :
i = 0,1,2;
相当于:
(i = 0),1,2;
所以i
将得到0
的值,并进一步评估的结果被丢弃。
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);
1。
int i, j; i = 3,0,1,2; printf("%d\n", i); => prints 3
2。
i = 3,j =7; printf("%d, %d\n", i, j); => prints 3 and 7
i = 3,0,1,2;
这将3 to i
分配3 to i
,然后执行0, 1 and 2
。 检查我提到的第二个例子。
另外,试试i=3;0;1;2;
这不会报告任何错误。 它只会执行(i=3), (0), (1) and (2)
。