括号是否始终被视为函数调用?

Are parentheses always considered a function call?

我正在查看此页面:https://en.cppreference.com/w/c/language/operator_precedence

引起我注意的是,括号运算符的描述是函数调用。这是否意味着表达式 x = a * (b+c)-(d*e) 有两个函数调用?

我在 C grammar and C standard 中进行了搜索,但找不到任何支持或反驳这一点的内容。

没有。 identifier( 将 identifier 作为函数调用。如果紧靠括号左侧没有标识符或完整表达式,则没有调用。

当我第一次学习 c 时,我遇到了相反的问题。我不明白为什么 clrscr; 没有清除屏幕。 (这是一个表达式,计算结果为指向 clrscr 的指针,但不对其执行任何操作)。

其实你可以有函数指针类型的表达式,这些表达式可以用()调用,两者的语法完全没有歧义。所以clrscr();是函数调用,(clrscr)()也是。在到达函数指针时,我们也可以做 resolve_function()() 。操作总是紧跟在表达式之后,而不是在运算符之后。如果在运算符之后,则必须是分组括号。

括号可以用作函数调用运算符,但这并不是它们的唯一用途。它们也用于您的示例中的表达式分组。

您要查找的是 C standard 的第 6.5.1 节,其中讨论了主要表达式:

Syntax

1

primary-expression:
  identifier
  constant
  string-literal
  ( expression )
  generic-selection

...

5 A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.

如上所述,括号可用于对表达式进行分组。

关于后缀表达式的第 6.5.2 节详细介绍了作为函数调用运算符的用法:

postfix-expression:
  ...
  postfix-expression(argument-expression-list opt)
  ...

所以在你的表达中:

x = a * (b+c)-(d*e)

此处括号的使用匹配主表达式而不匹配后缀表达式。

此外,除了表达式分组外,括号还用于语言语法的其他部分。关于选择语句的第 6.8.4 节在 ifswitch 语句的语法中使用括号:

  • if (expression) statement
  • if (expression) statement else statement
  • switch (expression) statement

关于迭代语句的第 6.8.5 节也在 whilefor 语句的语法中使用括号。

  • while (expression) statement
  • do statement while (expression);
  • for (expressionopt; expressionopt; expressionopt) statement
  • for (declaration expressionopt; expressionopt ) statement

函数调用是后缀表达式。

在这些表达式中

x = a * (b+c)-(d*e);

子表达式 (b+c)(d*e) 是主要表达式。您可以将任何表达式括在括号中,您将得到一个主要表达式。

例如,您甚至可以按以下方式重写表达式语句

( x = ( ( ( a ) * (b+c) )-(d*e) ) );

在这个表达式语句中有以下主要表达式

( a )
(b+c)
(d*e)
( ( a ) * (b+c) )
( ( ( a ) * (b+c) )-(d*e) )
( x = ( ( ( a ) * (b+c) )-(d*e) ) )

这里有一些后缀表达式的例子

( *p )() // a function call

a[n] // using the subscript operator

x++; // using the postfix increment operator

一个函数调用的定义是

postfix-expression:
    primary-expression
    postfix-expression ( argument-expression-listopt )

来自 C 标准(6.5.2.2 函数调用)

1 The expression that denotes the called function92) shall have type pointer to function returning void or returning a complete object type other than an array type.

这里有一些奇怪的函数调用的例子。:)

#include <stdio.h>

void f( void )
{
    printf( "Hello " );
}

void g( void )
{
    puts( "Broman" );
}    

int main( void )
{
    void ( *funcs[] )( void ) = { f, g };

    void ( **p_func )( void ) = funcs;

    ( *p_func++ )();
    p_func[0]();
}

程序输出为

Hello Broman

考虑到在这些调用中

    ( *p_func++ )();
    p_func[0]();

表达式( *p_func++ )是主表达式,表达式p_func[0]是后缀表达式(参见上面后缀表达式的部分定义)