我正在讨论C操作符的结合性。
在这里我发现了这样一个事实,即函数调用运算符()
具有从左到右的结合性。但是,只有当表达式中出现多个具有相同优先级的操作符时,结合性才会发挥作用。但是我找不到任何涉及函数调用运算符的例子,其中结合律起着至关重要的作用。
例如,在语句a = f(x) + g(x);
中,结果取决于求值顺序,而不是两个函数调用的结合性。类似地,调用f(g(x))
将首先求函数g()
,然后求函数f()
。这里我们有一个嵌套的函数调用,同样,结合律没有起任何作用。
该优先级组中的其他C操作符是数组下标[]
、postfix ++
和postfix --
。但是我找不到任何涉及这些操作符与()
的组合的例子,其中结合律在表达式求值中起作用。
所以我的问题是函数调用的结合性被定义为从左到右影响C中的任何表达式吗?任何人都可以提供一个例子,其中函数调用运算符()
的结合性在表达式评估中是否重要?
下面是一个函数调用操作符左右结合性的例子:
#include <stdio.h>
void foo(void)
{
puts("foo");
}
void (*bar(void))(void) // bar is a function that returns a pointer to a function
{
puts("bar");
return foo;
}
int main(void)
{
bar()();
return 0;
}
函数调用:
bar()();
等价于:
(bar())();
除了@GrzegorzSzpetkowski的回答,你还可以有以下内容:
void foo(void) { }
int main(void) {
void (*p[1])(void);
p[0] = foo;
p[0]();
return 0;
}
这将创建一个函数指针数组,因此可以将数组下标操作符与函数调用操作符一起使用。
函数应用程序关联到左边的语句在C语言定义中是完全冗余的。这种"结合性"隐含在函数参数列表出现在函数表达式本身的右边,并且必须包含在圆括号中。这意味着对于给定的函数表达式,其参数列表的范围永远不能有任何疑问:它从函数表达式后面的强制左括号扩展到匹配的右括号。
函数表达式(通常只是一个标识符,但可能更复杂)本身可能是一个(裸)函数调用,如f(n)(1,0)
中所示。(当然,这要求f(n)
返回的值是可以用参数列表(1,0)
调用的东西,C有一些可能性,c++更多,但这些是语义上的考虑,只有在解析之后才会发挥作用,所以在结合性讨论中应该忽略它们。)这意味着函数调用的语法规则是左递归的(函数部分本身可以是一个函数调用);这可以表述为"函数调用关联到左边",但事实是显而易见的。相比之下,右部分(参数列表)不能是(裸)函数调用,因为需要括号,所以不能有右递归。
以(a)(b)(c)
为例(我在这里添加了多余的括号,以暗示对称和可能的歧义)。这里的(b)(c)
本身可以被看作是对b
(加了多余括号)的调用,并带有参数c
;然而,这样的调用不能被解释为a
的参数,因为它需要像(a)((b)(c))
一样额外的括号。因此,在不提及结合性的情况下,很明显,(a)(b)(c)
只能意味着使用参数b
调用a
,并且使用参数c
调用结果值。