C 编译器如何知道函数调用中的逗号不是逗号运算符?

C 编译器如何知道函数调用中的逗号不是逗号运算符?,c,function,compiler-construction,comma-operator,C,Function,Compiler Construction,Comma Operator,考虑函数调用(调用intsum(int,int)) 编译器如何确定函数调用中使用的,和(int,int)不是逗号运算符 注意:我不想在函数调用中实际使用逗号运算符。我只是想知道编译器是如何知道它不是逗号运算符的。来自C99 6.5.17: 如语法所示,逗号运算符(如本款所述)不能 出现在使用逗号分隔列表中项目的上下文中(例如函数或列表的参数) 初始值设定者的名称)。另一方面,它可以在带括号的表达式中使用,也可以在第二个表达式中使用 在这种上下文中条件运算符的表达式。在函数调用中 f(a, (t=

考虑函数调用(调用
intsum(int,int)

编译器如何确定函数调用中使用的
和(int,int)不是逗号运算符

注意:我不想在函数调用中实际使用逗号运算符。我只是想知道编译器是如何知道它不是逗号运算符的。

来自C99 6.5.17:

如语法所示,逗号运算符(如本款所述)不能 出现在使用逗号分隔列表中项目的上下文中(例如函数或列表的参数) 初始值设定者的名称)。另一方面,它可以在带括号的表达式中使用,也可以在第二个表达式中使用 在这种上下文中条件运算符的表达式。在函数调用中

f(a, (t=3, t+2), c)
该函数有三个参数,第二个参数的值为5

另一个类似的示例是数组或结构的初始值设定项列表:

int array[5] = {1, 2};
struct Foo bar = {1, 2};
如果要将逗号运算符用作函数参数,请按如下方式使用:

sum((a,b))
当然,这不会编译。

如语法所示,逗号运算符(如本款所述)不能 出现在使用逗号分隔列表中项目的上下文中(例如函数的参数或初始值设定项列表)。另一方面,在这样的上下文中,它可以在带括号的表达式中使用,也可以在条件运算符的第二个表达式中使用。在函数调用
f(a,(t=3,t+2),c)
中,函数有三个参数,第二个参数的值为5


换句话说,“因为”

看看C语言的语法。该文件的附录A中列出了该文件的全部内容。它的工作方式是,您可以单步遍历C程序中的每个标记,并将它们与语法中的下一项匹配。在每个步骤中,您只有有限数量的选项,因此任何给定字符的解释将取决于其出现的上下文。在语法中的每个规则中,每一行都为程序提供了一个要匹配的有效替代项

具体来说,如果您查找
参数列表
,您将看到它包含一个显式逗号。因此,每当编译器的C解析器处于“参数列表”模式时,它找到的逗号将被理解为参数分隔符,而不是逗号运算符。括号也是如此(也可以出现在表达式中)

这是因为
参数列表
规则小心地使用
赋值表达式
规则,而不仅仅是普通的
表达式
规则。
表达式可以包含逗号,而
赋值表达式不能包含逗号。如果不是这种情况,语法将是不明确的,编译器将不知道在参数列表中遇到逗号时该怎么办


但是,例如,不属于函数定义/调用的一部分的左括号,或
if
while
for
语句的
将被解释为表达式的一部分(因为没有其他选项,但仅当表达式的开头在该点是有效的选择时),然后,在括号内,将应用
表达式
语法规则,这允许使用逗号运算符。

原因是C语法。虽然其他人似乎都喜欢引用这个例子,但真正的问题是标准(C99)中函数调用的短语结构语法。是的,函数调用由应用于后缀表达式(例如标识符)的
()
运算符组成:

连同

argument-expression-list:
       assignment-expression
       argument-expression-list , assignment-expression    <-- arglist comma

expression:
       assignment-expression
       expression , assignment-expression                  <-- comma operator
参数表达式列表:
赋值表达式
参数表达式列表,赋值表达式现有答案说“因为C语言规范说它是列表分隔符,而不是运算符”

但是,您的问题是“编译器如何知道…”,这完全不同:它与编译器如何知道
printf(“Hello,world\n”)中的逗号没有什么不同
不是逗号运算符:编译器“知道”是因为逗号出现的上下文-基本上是之前的内容

C‘语言’可以用(BNF)来描述——本质上是编译器用来扫描输入文件的一组规则。C的BNF将区分该语言中可能出现的逗号


关于编译器如何工作,有很多很好的参考资料。

这个问题有多个方面。一个定义是这样定义的。那么,编译器如何知道这个逗号在什么上下文中呢?这是解析器的工作。特别是对于C语言,该语言可以由LR(1)解析器()解析

其工作方式是解析器生成一组表,这些表构成解析器的可能状态。只有一组特定的符号在某些状态下有效,并且这些符号在不同的状态下可能具有不同的含义。由于前面的符号,解析器知道它正在解析函数。因此,它知道可能的状态不包括逗号运算符


我在这里非常笼统,但是你可以在维基上看到所有的细节

对,但不是问题的答案。@Yu:我不想使用逗号运算符。我只是想知道编译器是如何知道它不是逗号运算符的@sasha.sochka见OP的评论。他想知道解析器是如何工作的,而不是如何在函数调用中使用逗号。@haccks知道了,编辑了我的文字。使用逗号运算符作为函数参数并没有实际用处,但知道如何使用它仍然很有趣,所以我将保留这一部分。@YuHao;谢谢你,伙计!至少同时也感谢你编辑我的帖子。你说的是两个逗号中的哪一个…为什么人们投票来结束这个!!!!!!!!对此有不同意见
 6.5.2 postfix-expression:
       ...
       postfix-expression ( argument-expression-list_opt )
argument-expression-list:
       assignment-expression
       argument-expression-list , assignment-expression    <-- arglist comma

expression:
       assignment-expression
       expression , assignment-expression                  <-- comma operator