括号是否始终被视为函数调用?
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 节在 if
和 switch
语句的语法中使用括号:
- if (expression) statement
- if (expression) statement else statement
- switch (expression) statement
关于迭代语句的第 6.8.5 节也在 while
和 for
语句的语法中使用括号。
- 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]
是后缀表达式(参见上面后缀表达式的部分定义)
我正在查看此页面: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 节在 if
和 switch
语句的语法中使用括号:
- if (expression) statement
- if (expression) statement else statement
- switch (expression) statement
关于迭代语句的第 6.8.5 节也在 while
和 for
语句的语法中使用括号。
- 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]
是后缀表达式(参见上面后缀表达式的部分定义)