C中函数调用运算符的结合性
Associativity of function call operator in C
我正在讨论 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语言定义中完全是多余的。 "associativity" 暗示函数参数列表出现在函数表达式本身的右侧,并且 必须括在圆括号 中。这意味着对于给定的函数表达式,其参数列表的范围永远不会有任何疑问:它从函数表达式之后的强制左括号延伸到匹配的右括号。
函数表达式(通常只是一个标识符,但可能更复杂)本身可能是一个(纯)函数调用,如 f(n)(1,0)
中所示。 (当然,这需要 f(n)
返回的值是可以用参数列表 (1,0)
调用的东西,为此 C 有一些可能性,C++ 有更多,但这些是语义上的考虑,仅come to play after parsing, 所以在结合性讨论中应该忽略它们。)这意味着函数调用的语法规则是左递归的(函数部分本身可以是函数调用) ;这可以用 "function calls associate to the left" 来表述,但事实是显而易见的。相比之下,由于需要括号,右侧部分(参数列表)不能是(裸)函数调用,因此不可能有正确的递归。
例如考虑 (a)(b)(c)
(我在其中放置了多余的括号以暗示对称性和可能的歧义)。这里 (b)(c)
本身可能被认为是带有参数 c
的 b
(冗余括号)的调用;然而,这样的调用不能被解释为 a
的参数,因为这需要像 (a)((b)(c))
中那样的额外括号。因此,如果不提及关联性,很明显 (a)(b)(c)
只能表示 a
以参数 b
调用,结果值以参数 c
调用。
我正在讨论 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语言定义中完全是多余的。 "associativity" 暗示函数参数列表出现在函数表达式本身的右侧,并且 必须括在圆括号 中。这意味着对于给定的函数表达式,其参数列表的范围永远不会有任何疑问:它从函数表达式之后的强制左括号延伸到匹配的右括号。
函数表达式(通常只是一个标识符,但可能更复杂)本身可能是一个(纯)函数调用,如 f(n)(1,0)
中所示。 (当然,这需要 f(n)
返回的值是可以用参数列表 (1,0)
调用的东西,为此 C 有一些可能性,C++ 有更多,但这些是语义上的考虑,仅come to play after parsing, 所以在结合性讨论中应该忽略它们。)这意味着函数调用的语法规则是左递归的(函数部分本身可以是函数调用) ;这可以用 "function calls associate to the left" 来表述,但事实是显而易见的。相比之下,由于需要括号,右侧部分(参数列表)不能是(裸)函数调用,因此不可能有正确的递归。
例如考虑 (a)(b)(c)
(我在其中放置了多余的括号以暗示对称性和可能的歧义)。这里 (b)(c)
本身可能被认为是带有参数 c
的 b
(冗余括号)的调用;然而,这样的调用不能被解释为 a
的参数,因为这需要像 (a)((b)(c))
中那样的额外括号。因此,如果不提及关联性,很明显 (a)(b)(c)
只能表示 a
以参数 b
调用,结果值以参数 c
调用。