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

时间:2019-05-22 13:48:26

标签: c operator-precedence

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

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

我在C grammarC standard中进行了搜索,但找不到任何支持或矛盾的内容。

3 个答案:

答案 0 :(得分:6)

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

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

  

语法

     

1

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

...

     

5 带括号的表达式是主要表达式。其类型和值与未带括号的表达式相同   表达。它是左值,函数指示符或无效值   如果未加括号的表达式分别是   一个左值,一个函数指示符或一个空表达式。

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

在6.5.2节中有关Postfix表达式的详细信息,用作函数调用运算符:

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

在您的表情中:

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

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

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

  
      
  • 如果(表达式声明
  •   
  • if( expression statement else statement
  •   
  • switch( expression statement
  •   

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

  
      
  • while( expression statement
  •   
  • 在(表达)时执行声明
  •   
  • 表示( expression opt ; expression opt ; expression opt 声明
  •   
  • 表示(声明 expression opt ; expression opt 声明
  •   

答案 1 :(得分:4)

函数调用是后缀表达式。

这些表达方式在这里

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

subexpressioins (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表示被调用函数(92)的表达式应具有类型   指向返回void或返回完整对象类型的函数的指针   除了数组类型。

以下是一些奇怪的函数调用示例::)

#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]是后缀表达式(请参见上面的后缀表达式的部分定义)

答案 2 :(得分:2)

不。 identifier(将标识符作为函数调用。如果没有标识符或括号后紧跟的完整表达式,则不会调用。

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

实际上,您可以具有指向函数的类型指针的表达式,并且可以使用()调用这些表达式,并且两者之间的语法是完全明确的。因此clrscr();是一个函数调用,(clrscr)()也是如此。在到达函数指针时,我们也可以执行resolve_function()()。该操作始终(在表达式之后,而不是在运算符之后。如果是在运算符之后,则必须将括号分组。