Je regardais cette page: https://en.cppreference.com/ w / c / language / operator_precedence
Ce qui a attiré mon attention, c'est que la seule description de l'opérateur entre parenthèses était un appel de fonction . Cela signifie-t-il que l'expression x = a * (b + c) - (d * e)
a deux appels de fonction?
J'ai cherché dans la grammaire C et < a href = "https://port70.net/~nsz/c/c11/n1570.html" rel = "nofollow noreferrer"> C standard mais je n'ai rien trouvé qui soutienne ou contredit cela.
3 Réponses :
Non. identifiant (appelle l'identifiant en tant que fonction. S'il n'y a pas d'identifiant ou d'expression complète immédiatement à gauche des parenthèses, il n'y a pas d'appel.
Quand j'ai appris c, j'ai eu le problème inverse. Je n'ai pas pu comprendre pourquoi clrscr;
n'a pas effacé l'écran. (C'est une expression qui évalue un pointeur vers clrscr
mais ne fait rien avec).
En fait, vous pouvez avoir des expressions de type pointeur vers une fonction, et ces expressions peuvent être appelées avec (), et la grammaire est sans ambiguïté entre les deux. Donc clrscr ();
est un appel de fonction, tout comme (clrscr) ()
. En atteignant les pointeurs de fonction, nous pouvons également faire resolution_function () ()
. L'opération est toujours (immédiatement après une expression, pas après un opérateur. Si c'est après un opérateur, elle doit être entre parenthèses de regroupement.
La grammaire d'un appel de fonction est « expression-postfixe (
liste-expression-argument )
», où le argument-expression-list est facultatif. L ' expression-postfixe n'a pas besoin d'être un identifiant. Il peut s'agir d'un pointeur vers une fonction, voire d'un appel de fonction qui renvoie un pointeur vers une fonction.
@EricPostpischil: Vous avez raison. J'ai fait une supposition au niveau de l'OP et j'ai écrit en conséquence.
Vous pouvez modifier votre réponse. Je suis souvent confronté au problème de m'adresser à un novice tout en voulant également présenter la vérité complète, et il existe différentes approches. Vous pouvez écrire que « identificateur (
arguments )
» est toujours un appel de fonction, et que les parenthèses sans expression immédiatement avant eux se trouvent une expression entre parenthèses ou un cast (et non un appel de fonction), puis vous pouvez ajouter plus tard que « postfix-expression (
arguments i> )
”est également un appel de fonction, qui est utilisé avec des pointeurs vers des fonctions ainsi que des noms de fonction.
Il pourrait également être bon de mentionner que la grammaire C, qui est une description formelle de la structure du code source C, permet toujours de les distinguer.
Les parenthèses peuvent être utilisées comme opérateur d'appel de fonction, mais ce n'est pas la seule chose pour laquelle elles sont utilisées. Ils sont également utilisés pour le regroupement d'expressions comme dans votre exemple.
Ce que vous recherchez est dans la section 6.5.1 du C standard qui traite des expressions primaires:
Syntaxe
1
x = a * (b+c)-(d*e)...
5 Une expression entre parenthèses est une expression principale. Son type et sa valeur sont identiques à ceux des expressions sans parenthèse. expression. C'est une lvalue, un désignateur de fonction ou un vide expression si l'expression sans parenthèse est, respectivement, une lvalue, un indicateur de fonction ou une expression vide.
Comme indiqué ci-dessus, les parenthèses peuvent être utilisées pour regrouper des expressions.
L'utilisation comme opérateur d'appel de fonction est détaillée dans la section 6.5.2 sur les expressions Postfix:
postfix-expression: ... postfix-expression(argument-expression-list opt) ...
Donc dans votre expression:
primary-expression: identifier constant string-literal ( expression ) generic-selection
L'utilisation de parenthèses ici correspond à une expression principale mais pas à une expression Postfix.
Aussi , outre le regroupement d'expressions, les parenthèses sont utilisées dans d'autres parties de la grammaire du langage. La section 6.8.4 concernant les instructions de sélection utilise des parenthèses dans la grammaire des instructions if
et switch
:
- if ( expression ) déclaration
- if ( expression ) instruction else déclaration
- commutateur ( expression ) déclaration
Et la section 6.8.5 concernant les instructions d'itération utilise également des parenthèses dans la grammaire de tandis que
et pour les instructions
.
- while ( expression ) déclaration
- do instruction while ( expression );
- pour ( expression opt ; expressionopt ; expression opt sub > ) déclaration
- pour ( déclaration expressionopt ; expressionopt ) déclaration
Pourriez-vous ajouter quelque chose sur le fait que les parenthèses ne sont pas toujours considérées comme un opérateur. C'est ce qui semble être (un de) mes malentendus.
Un appel de fonction est une expression de suffixe.
Ici, dans ces expressions
( *p_func++ )(); p_func[0]();
sous-expressions (b + c)
et (d * e)
sont des expressions primaires. Vous pouvez mettre n'importe quelle expression entre parenthèses et vous obtiendrez une expression principale.
Par exemple, vous pouvez même réécrire l'instruction d'expression de la manière suivante
Hello Broman
Dans cette instruction d'expression, il y a les expressions primaires suivantes
#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](); }
Voici quelques exemples d'expressions postfixes
postfix-expression: primary-expression postfix-expression ( argument-expression-listopt )
La définition de un appel de fonction est
( *p )() // a function call a[n] // using the subscript operator x++; // using the postfix increment operator
De la norme C (6.5.2.2 Appels de fonction)
1 L'expression qui désigne la fonction appelée 92) doit avoir le type pointeur vers la fonction renvoyant void ou renvoyant un type d'objet complet autre qu'un type de tableau.
Voici quelques exemples d'appels de fonction étranges .:)
( a ) (b+c) (d*e) ( ( a ) * (b+c) ) ( ( ( a ) * (b+c) )-(d*e) ) ( x = ( ( ( a ) * (b+c) )-(d*e) ) )
La sortie du programme est
( x = ( ( ( a ) * (b+c) )-(d*e) ) );
Tenez compte du fait que dans ces appels
x = a * (b+c)-(d*e);
expression (* p_func ++)
est une expression primaire et une expression p_func [0] est une expression postfix (voir la définition partielle de l'expression postfix ci-dessus)
(* p) ()
et (* p)
sont tous deux postfix-expression , peut-être légèrement déroutant pour le débutant. Quand on parle d'appels de fonction, le terme «l'expression postfixe» fait normalement référence à l'expression avant l'opérateur d'appel de fonction.
Non, les parenthèses sont utilisées tout autant pour forcer la priorité des opérateurs, exactement comme cela se fait en mathématiques simples.
opérateur de parenthèses
.. intéressant, où avez-vous trouvé cela?Cela signifie que lorsque
()
est utilisé pour un appel de fonction (peu importe comment il peut être utilisé), il a la priorité 1. Un peu plus bas, vous pouvez voir(type) Type cast < / code> avec la priorité 2, par exemple.
Il semble que vous ayez manqué certains chapitres de la norme. Ex. 6.5.1p5
Essayez de rechercher la page de grammaire C pour
'('
. Ils sont utilisés dans beaucoup plus d'endroits que juste dans les expressions postfixes (=> appels de fonction).x = a * (b + c) - (d * e)
est une expression, pas une instruction. Ici(
n'est pas un opérateur. Le terme "opérateur parenthèses" fait référence à l'endroit où()
est utilisé comme opérateur. De même dansint * p = 0; < / code> les
*
et=
ne sont pas des opérateurs, même si les mêmes symboles sont utilisés pour les opérateurs dans des contextes différents@KamilCuk Alors ce que vous dites est cette expression principale et que () n'est PAS un opérateur?
port70.net/~nsz/c/c11/n1570.html# 6.5.1
@SouravGhosh Sur la page que j'ai liée.
@Broman Relisez celui-là. C'est un opérateur d'appel de fonction, pas un opérateur de parenthèse.
@SouravGhosh Les parenthèses régulières ne sont donc pas un opérateur?
@Broman Non, ils ne le sont pas.
La racine du problème est que la table de préséance liée est complète et complète. Il y a tellement de mal à cela que nous devrions demander à cppréférence de fermer cette page. Il ne peut pas être sauvé.
@Lundin Cela semble être une bonne base pour une bonne réponse. J'ai fait une réponse une fois basée sur une diatribe sur tutorialspoint.
Il semble que (l'un de) mon malentendu soit de supposer que les parenthèses régulières sont considérées comme des opérateurs, mais aucune réponse ci-dessous ne touche ce problème particulier
@Lundin Vraiment? J'ai trouvé que c'était une bonne référence qui aide le lecteur moyen à comprendre la priorité des opérateurs sans avoir à utiliser la grammaire complète de la langue du standard.
@Lundin Le voici: stackoverflow.com/a/55731680/6699433
Une fois, j'ai lancé un projet pour fournir une table de préséance fiable pour SO, mais il s'est échoué. Ma principale objection contre la cppreference est de mauvais noms pour presque tous les opérateurs.