hac*_*cks 37 c compiler-construction function comma-operator
考虑函数调用(调用int sum(int, int))
printf("%d", sum(a,b));
Run Code Online (Sandbox Code Playgroud)
编译器如何确定,函数调用中使用的函数sum(int, int)不是逗号运算符?
注意:我不想在函数调用中实际使用逗号运算符.我只是想知道编译器如何知道它不是逗号运算符.
ams*_*ams 49
看一下C语言的语法.它已在标准的附录A中全部列出.它的工作方式是你可以逐步执行C程序中的每个标记,并将它们与语法中的下一个项目进行匹配.在每个步骤中,您只有有限数量的选项,因此任何给定字符的解释将取决于它出现的上下文.在语法中的每个规则内,每一行都为程序提供了一个有效的替代方案.
具体来说,如果您查找parameter-list,您将看到它包含一个明确的逗号.因此,只要编译器的C解析器处于"参数列表"模式,它找到的逗号将被理解为参数分隔符,而不是逗号运算符.括号也是如此(也可以出现在表达式中).
这是有效的,因为parameter-list规则要小心使用assignment-expression规则,而不仅仅是普通expression规则.一个expression可以包含逗号,而一个assignment-expression不能.如果不是这种情况,语法将是模糊的,并且编译器在参数列表中遇到逗号时将不知道该怎么做.
但是,左括号,例如,是不是一个函数的定义/调用的一部分,或者if,while或者for声明,将被解释为一个表达式的一部分(因为没有其他选择,但只有一个表达式的开始在那一点上是一个有效的选择),然后,在括号内,expression语法规则将适用,并允许逗号运算符.
Yu *_*Hao 26
从C99 6.5.17:
如语法所示,逗号运算符(如本子条款中所述)不能出现在使用逗号分隔列表中的项的上下文中(例如函数的参数或初始化列表).另一方面,它可以在括号内表达式中使用,也可以在这种上下文中的条件运算符的第二个表达式中使用.在函数调用中
Run Code Online (Sandbox Code Playgroud)f(a, (t=3, t+2), c)该函数有三个参数,第二个参数的值为5.
另一个类似的例子是数组或结构的初始化列表:
int array[5] = {1, 2};
struct Foo bar = {1, 2};
Run Code Online (Sandbox Code Playgroud)
如果要将逗号运算符用作函数参数,请像这样使用它:
sum((a,b))
Run Code Online (Sandbox Code Playgroud)
当然,这不会编译.
Jen*_*ens 19
原因是C语法.虽然其他人似乎都想引用这个例子,但实际的交易是标准(C99)中函数调用的短语结构语法.是的,函数调用包含()应用于后缀表达式的运算符(例如标识符):
6.5.2 postfix-expression:
...
postfix-expression ( argument-expression-list_opt )
Run Code Online (Sandbox Code Playgroud)
和...一起
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression <-- arglist comma
expression:
assignment-expression
expression , assignment-expression <-- comma operator
Run Code Online (Sandbox Code Playgroud)
逗号运算符只能出现在表达式中,即在语法中进一步向下.因此编译器将函数参数列表中的逗号视为分隔赋值表达式的逗号,而不是分隔表达式.
Rod*_*ddy 11
现有的答案说"因为C语言规范说它是列表分隔符,而不是运算符".
但是,你的问题是"编译器如何知道...",这完全不同:它与编译器知道逗号printf("Hello, world\n");不是逗号运算符的方式完全没有区别:编译器'知道'因为逗号出现的上下文 - 基本上,以前的内容.
C'语言'可以用Backus-Naur形式(BNF)来描述- 实质上是编译器的解析器用来扫描输入文件的一组规则.BNF for C将区分语言中这些不同可能出现的逗号.
关于编译器如何工作以及如何编写编译器有很多很好的资源.