为什么这个逗号的使用在表达式中起作用但在声明中失败?

来自高级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; 

是一种表达方式。

在表达式中,我们可以使用逗号运算符来评估左侧( 通常用于副作用 ),抛弃结果然后评估右侧等…

在声明中,逗号是语法分隔符而不是逗号运算符。 ,分隔声明符,因为12不是声明上下文中的声明符,这是不正确的语法:

  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 ,它可以是声明符声明器=初始化器, 12都不是声明符 ,因此我们的语法不正确。

初始值设定项可以是赋值表达式,但这个表达式并没有为我们提供一个裸逗号运算符的路径,尽管我们最终可能会在()通过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 ,然后是表达式12并将结果抛出。

第二个例子

 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)