Всегда ли круглые скобки считаются вызовом функции? - PullRequest
5 голосов
/ 22 мая 2019

Я смотрел на этой странице: https://en.cppreference.com/w/c/language/operator_precedence

Что привлекло мое внимание, так это то, что описание оператора скобок only было вызовом функции . Означает ли это, что выражение x = a * (b+c)-(d*e) имеет два вызова функций?

Я искал в C грамматике и C стандарте , но мне не удалось найти ничего, что либо поддерживает, либо противоречит этому.

Ответы [ 3 ]

6 голосов
/ 22 мая 2019

Скобки можно использовать как оператор вызова функции, но это не единственное, для чего они используются. Они также используются для группировки выражений, как в вашем примере.

То, что вы ищете, находится в разделе 6.5.1 стандарта C , в котором обсуждаются основные выражения:

Синтаксис

1

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

...

5 Выражение в скобках является основным выражением. Его тип и значение идентичны тем, которые указаны в скобках выражение. Это lvalue, обозначение функции или пустота выражение, если выражение без скобок, соответственно, lvalue, обозначение функции или выражение void.

Как указано выше, скобки можно использовать для группировки выражений.

Использование в качестве оператора вызова функции подробно описано в разделе 6.5.2 о выражениях Postfix:

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

Итак, в вашем выражении:

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

Использование круглых скобок здесь соответствует первичному выражению, но не выражению Postfix.

Кроме того, помимо группировки выражений, круглые скобки используются в других частях грамматики языка. Раздел 6.8.4, касающийся операторов выбора, использует круглые скобки в грамматике операторов if и switch:

  • if ( выражение ) выражение
  • if ( выражение ) оператор else оператор
  • переключатель ( выражение ) оператор

И раздел 6.8.5, касающийся итерационных операторов, также использует круглые скобки в грамматике операторов while и for.

  • while ( выражение ) выражение
  • do оператор while ( выражение );
  • для ( выражение opt ; выражение opt ; выражение opt ) заявление
  • для ( декларация выражение opt ; выражение opt ) выражение
4 голосов
/ 22 мая 2019

Вызов функции - это постфиксное выражение.

Вот в этих выражениях

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 голосов
/ 22 мая 2019

Нет.идентификатор (вызывает идентификатор как функцию. Если сразу же из скобок не осталось идентификатора или полного выражения, вызова нет.

Когда я только начинал изучать c, у меня возникла противоположная проблема. Я не мог понять, почемуclrscr; не очистил экран. (Это выражение, которое оценивает указатель на clrscr, но ничего с ним не делает).

На самом деле вы можете иметь выражения типа указатель на функцию, и этиВыражения можно вызывать с помощью (), и грамматика между ними совершенно однозначна. Так что clrscr(); - это вызов функции, как и (clrscr)(). При достижении указателей на функции мы можем также сделать resolve_function()(). Операциявсегда (сразу после выражения, а не после оператора. Если это после оператора, это должно быть группировка скобок.

...