C语言中函数调用算子的结合性

C语言中函数调用算子的结合性,c,associativity,C,Associativity,我正在讨论C操作符的结合性 在那里,我遇到了这样一个事实:函数调用操作符()具有从左到右的关联性。但只有当一个表达式中出现多个具有相同优先级的运算符时,关联性才会发挥作用。但我找不到任何涉及函数调用操作符的例子,其中关联性起着至关重要的作用 例如在语句a=f(x)+g(x)中,结果取决于求值顺序,而不是两个函数调用的关联性。 类似地,调用f(g(x))将首先计算函数g(),然后计算函数f()。这里我们有一个嵌套函数调用,关联性也不起任何作用 此优先级组中的其他C运算符是数组下标[],后缀+和后缀

我正在讨论C操作符的结合性

在那里,我遇到了这样一个事实:函数调用操作符
()
具有从左到右的关联性。但只有当一个表达式中出现多个具有相同优先级的运算符时,关联性才会发挥作用。但我找不到任何涉及函数调用操作符的例子,其中关联性起着至关重要的作用

例如在语句
a=f(x)+g(x)中,结果取决于求值顺序,而不是两个函数调用的关联性。
类似地,调用
f(g(x))
将首先计算函数
g()
,然后计算函数
f()
。这里我们有一个嵌套函数调用,关联性也不起任何作用

此优先级组中的其他C运算符是数组下标
[]
后缀+
后缀--
。但我找不到任何涉及这些运算符与
()
组合的示例,其中关联性在表达式求值中起作用


所以我的问题是,从左到右定义函数调用的关联性是否会影响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())();

除了@grzegorzzpetkowski的答案外,您还可以获得以下内容:

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)
显然只能意味着
a
是通过参数
b
调用的,结果值是通过参数
c

调用的,如果
f
是一个表达式本身(如从数组中选择的一个函数指针),该怎么办?任何返回函数指针的函数都可以用作示例,因为函数调用运算符不需要函数指针解引用。因此,你开始使用类似于
f()
的东西,它是有效的C。。。。它必须是从左到右的。你愿意生活在这样一个世界里吗?
f(a)(b)
是对
f
的一个调用,通过
b
然后用
a
调用结果(也就是说
(f(b))(a)
)-你愿意吗?我不同意现有的答案,不管投票结果如何。他们确实很好地解释了一些基本原理,但却深入了很多。是的,关于C语法区分“主”和“一元”运算符,我们可能有很长的争论,但这种区分也只是语法的产物。非常感谢。在处理所有前缀或后缀的一元运算符时,关联性在什么意义上相关?我认为它主要适用于前缀和后缀运算符都应用于同一项的情况,如
*foo()
。我想不出任何关于
foo
的定义会允许
(*foo)(
*(foo())
在C语言中是合法的(这样的事情在C++中可能存在),但事实是,在某些情况下,每种形式都是合法的,只有后者可以用
*foo()替换
将证明
*
()
@GrzegorzSzpetkowski的相对关联性:在我看来,如果它们真的是运算符,那么就有可能写出类似
foo->(expr?bar:boz)
的东西,并且其意义等同于
expr?foo->bar:foo->boz
(事实上,想想看,使用C语言可以使某些代码更清晰,并且不会使任何当前的法律结构变得模棱两可;但是,这将严重违反“无新发明”规则)。尽管如此,我认为说二进制运算符连接表达式更有用,因此
->
不是二进制运算符,而不是考虑这些东西…@super
void foo(void) { }

int main(void) {
    void (*p[1])(void);
    p[0] = foo;
    p[0]();
    return 0;
}