next up previous contents index
Next: 3 Structures de contrôle Up: Le langage C Previous: 1 Eléments de base

Subsections


2 Opérateurs et expressions

    

2.1 Généralités sur les opérateurs

Une expression est un objet syntaxique obtenu en assemblant ``correctement'' des constantes, des variables et des opérateurs. Par exemple, l'expression x +3 est une expression. Dans le langage C, il y a bien d'autres opérateurs que les opérateurs arithmétiques qu'on a l'habitude de manipuler; il y en a, en fait, plus de quarante opérateurs.

2.1.1 Notation infixée, préfixée et postfixée.

Il nous est naturel d'écrire l'addition de deux nombres sous la forme a + b .

Cela vient de notre culture mathématique. Cette notation n'est qu'une convention choisie par nos ancêtres; ce n'est pas la seule possible. Nos ancêtres auraient très bien pu convenir que cette addition se noterait + ab ou bien ab + .

Notation Nom
a + b infixé
+ ab préfixée ou polonaise
ab + postfixée ou polonaise inversée

L'avantage des notations préfixée et postfixée est qu'elles ne requierent pas de parenthèses. Par exemple, l'expression ( a + b )* c se note *+ abc en notation préfixée et ab + c* en notation postfixée. Plus concise, ces notations (préfixée et postfixée) sont plus adaptées pour les machines que pour nous; on y perd en clarté. Aussi, le langage C utilise la notation infixée pour les opérateurs et on y trouve

2.1.2 Opérateurs et priorités

   

Nous avons l'habitude de manipuler des expressions (par exemple arithmétiques) et il nous est relativement aisé de préciser exactement le sens des expressions comme : 2+3*4*5-2, 2-3-4 etc...

On sait que ces expressions sont équivalentes à (2+(3*(4*5)))-2, (2-3)-4. Introduire les paranthèses permet de définir sans ambiguïté l'expression que l'on manipule. A priori, c'est notre culture mathématique qui nous permet de parenthéser ces expressions. Pour éviter l'usage des parenthèses qui alourdissent la lecture, lorsque cela est posible, les mathématiciens ont fixé des règles pour que tout le monde parenthèse (dans sa tête) de la même manière toute expression ambigüe.

Par exemple, dans l'expression 2+3*4, la sous expression 3*4 est évaluée en premier et le résultat obtenu est ajouté à la valeur 2 (forme parenthésée : 2 + ( 3 * 4)). On dit que l'opérateur * possède une priorité supérieure à la priorité de l'opérateur +.

De même, dans l'expression 2-3-4, la sous expression 2-3 est évaluée en premier et, au résultat obtenu, on soustrait la valeur 4 (forme parenthésée : (2 - 3) - 4). On dit que l'ordre (d'évaluation) de l'opérateur - est de gauche à droite.

Comme nous le verrons plus loin, outre les expressions arithmétiques, le langage C dispose de beaucoup d'autres expressions. La donnée d'une priorité et d'un ordre d'évaluation permet de fixer des règles communes d'évaluation des expressions.

Ces priorités et ordre d'évaluation ne permettent évidemment pas de se dispenser complètement des parenthèses. En effet, on utilise les parenthèses lorqu'on veut évaluer une expression d'une manière autre que celle définie à l'aide de la priorité et de l'ordre d'évaluation. Par exemple, si l'on veut faire 2+3 et multiplier le résultat par 4, on notera (2+3)*4 et il n'est pas possible de l'écrire sans les paranthèses avec la notation infixée (sauf à développer l'expression).

Comme premier exemple d'opérateur, voici les caractéristiques de l'opérateur ()

Opérateur Nom Notation Priorité Ordre
() parenthèses (...) 15 gauche-droite

2.2 Les opérateurs du langage C

2.2.1 L'opérateur d'affectation

      L'opération la plus importante dans un langage de programmation est celle qui consiste à donner une valeur à une variable. Cette opération est désignée par le symbole =; nous l'avons déjà rencontré plus haut (voir section 1.6).

Le symbole = peut prêter à confusion. Il ne s'agit pas d'une équation au sens mathématique du terme. Il s'agit tout simplement de remplir une case mémoire avec une certaine valeur.

Le système d'équations {x=2, x=3} n'a pas de solution au sens mathématique; par contre les deux affectations successives x=2; x=3 est parfaitement valide[*] et correspond à ranger la valeur 2 puis la valeur 3 dans la zone mémoire allouée à la variable x . De même, l'équation {x=x+1} n'a pas de solution au sens mathématique; par contre l'affectations x=x+1 est parfaitement valide et consiste à incrémenter de 1 la valeur de la variable x .

Comme l'affectation range une valeur dans une variable (une zone mémoire), il est impératif que le membre gauche d'une affectation représente une zone mémoire : c'est ce qu'on appelle une lvalue (pour left value) . Une constante n'est pas une lvalue car il ne désigne pas l'adresse d'une zone mémoire. Elle ne peut donc pas figurer en membre gauche d'une affectation.

Le membre droit d'une affectation peut désigner soit une constante soit une zone mémoire soit une expression quelconque : l'affectation x=2 range la valeur 2 dans la variable x , l'affectation x=y range dans la variable x le contenu de la variable y et l'affectation x=y+1 range dans la variable x le contenu de la variable y incrémenté de 1.

Opérateur Nom Notation Priorité Ordre
= Affectation x = y 2 droite-gauche

L'affectation est une expression.

La valeur d'une affectation est la valeur de son membre gauche après exécution de l'affectation. Si la variable y contient la valeur 100 alors l'affectation x=y+20 a pour valeur 120.

Une affectation peut figurer en membre droit d'une autre affectation.

L'affectation x=y=1 est parfaitement valide car elle représente (voir ordre d'évaluation) l'affectation x=(y=1). Puisque y=1 est une expression, elle peut figurer donc en membre droit d'une affectation. Puisque elle est syntaxiquement juste, quel sens donner à cette affectation ? Puisque y=1 est une expression dont la valeur est la valeur de son membre gauche (ici la valeur entiere 1), l'affectation x=y=1 range dans la variable x la valeur 1 après avoir rangé dans y cette même valeur 1 . Ainsi, l'affectation x1=x2=x3=...=x20=0 est équivalent à la suite d'affectations (dans l'ordre indiqué) x20=0, x19=0, x18=0, ..., x1=0.

2.2.2 Les opérateurs arithmétiques

             

Opérateur Nom Notation Priorité Ordre
+ Addition x + y 12 gauche-droite
- soustraction x - y 12 gauche-droite
* multiplication x * y 13 gauche-droite
/ division x / y 13 gauche-droite
% modulo x % y 13 gauche-droite
Les opérateurs +, -, * fonctionnent comme on s'y attend. Par contre, l'opérateur / se comporte de manière différente selon que les opérandes sont des entiers ou des nombres flottants. Lorsqu'il s'agit de nombres flottants, le résultat est un nombre flottant obtenu en divisant les deux nombres (pas de surpise !). Lorsqu'il s'agit de nombres entiers, le résultat est un nombre entier obtenu en calculant la division entière. L'opérateur % n'est défini que pour les entiers et le résultat est le reste de la division entière des opérandes.

Rappel sur la division entière : On appelle quotient et reste de la division entière de a et de b , les nombres entiers q et r vérifiant

a = q * b + r; 0 < r < b

Exemple : Si a =20 et b =3 alors q =6 et r =2 (20 = 6 * 3 + 2).

Comme nous l'avons déjà vu, on peut appliquer des opérateurs arithmétiques sur les caractères (qui ne sont qu'un type d'entier particulier). On est donc autorisé à écrire, 'A'-'0', 'A'+1, etc...

L'opérateur unaire - a une priorité supérieure aux opérateurs binaires arithmétiques.

Opérateur Nom Notation Priorité Ordre
- (unaire) négation - x 14 droite-gauche

L'opérateur unaire + n'existe pas en C. Ce n'est qu'une notation et ce symbole est supprimé lors de l'analyse syntaxique.

2.2.3 Les opérateurs de comparaison

Opérateur Nom Notation Priorité Ordre
== test d'égalité x == y 9 gauche-droite
!= test de non-égalité x != y 9 gauche-droite
<= test d'inférieur ou égal x <= y 10 gauche-droite
>= test de supérieur ou égal x >= y 10 gauche-droite
<= test d'inférieur strict x < y 10 gauche-droite
>= test de supérieur strict x > y 10 gauche-droite

Théoriquement, le résultat d'une compraison est une valeur boolénne (vrai ou faux). Dans le langage C, le résultat d'une comparaison est 1 ou 0 selon que cette comparaison est vraie ou fausse.

Comme nous l'avons déjà signalé, il n'existe pas de type booléen en C; la valeur entière 0 sera considérée comme équivalente à la valeur faux et toute valeur différente de 0 équivalente à la valeur vrai [*].

Puisqu'une valeur boolénne est une valeur entière, on peut utiliser des expressions suivantes[*] 2, 0, x+2, x=2 , etc... comme si elles étaient des résultats de comparaison.

Attention !!!
Ne confondez pas == (test d'égalité) et = (affectation).

Cette confusion (souvent involontaire) est source de nombreuses erreurs. Cette confusion est d'autant plus facile à faire que les deux écritures sont syntaxiquement correctes :

if (x == 2) { ...   if (x = 2) { ...
La première teste l'égalité de la valeur contenue dans la variable x et la valeur 2 , alors que la deuxième teste la valeur de l'affectation x=2 qui vaut 2 quelle que soit la valeur de x (dans cet exemple). Ainsi, selon que la valeur contenue dans le varaible x est 2 ou pas, la première forme fera des choses différentes. Par contre, quelque soit la valeur de x , la valeur de l'expression x=2 est toujours 2.

2.2.4 Les opérateurs logiques

Rappel de logique

Une variable booléenne est une variable pouvant prendre la valeur vrai ou faux. On appelle calcul propositionnel (ou algèbre de Boole) l'étude des ensemble de formules fabriquées à partir des constantes booléennes (vrai ou faux), des variables boolénnes et des connecteurs logiques ~  (non logique), &  (et logique), | (ou logique).

On construit la table de vérité pour chacun des connecteurs :

a  
a  
~ a
vrai faux  
faux vrai  
     

Dans le langage C, on dispose de ces connecteurs (sous une syntaxe particulière) et on peut fabriquer des expressions avec celles-ci. La valeur d'une expression boolénne est, comme le résultat des comparaisons, une valeur entière.

Opérateur Nom Notation Priorité Ordre
&& ET x && y 5 gauche-droite
|| OU x || y 4 gauche-droite
! (unaire) NON ! x 14 droite-gauche
Une expression boolénne en C possède toujours une valeur; contrairement à l'algèbre de Boole, il n'y pas la notion de variable (au sens mathématique) boolénne.

Evaluation des expressions boolénnes

Comme pour les autres opérateurs, l'évaluation d'une expression boolénne obéit aux règles de priorité et à l'ordre d'évaluation. Il faut cependant préciser que cette évaluation s'arrête dès que l'on est capable de donner la valeur de l'expression. Par exemple, en supposant que la varibale x contient la valeur 5, l'évaluation de l'expression (x >= 2) || ( x >= y) s'arrête avant même d'avoir évalué l'expression x >= y, puisque (x >= 2) est vrai d'où on peut conclure que la valeur de l'expression (x >= 2) || ( x >= y) est également vraie.

Cette remarque a son importance dans deux cas:

2.2.5 Les opérateurs de manipulation de bits

Opérateur Nom Notation Priorité Ordre
& ET bit à bit x & y 8 gauche-droite
| OU bit à bit x | y 6 gauche-droite
^ OU exclisif bit à bit x ^ y 7 gauche-droite
~ (unaire) NON bit à bit ~ x 14 droite-gauche
>> décalage à droite >> x 11 droite-gauche
<< décalage à gauche << x 11 droite-gauche

Décalage de bits

2.2.6 Les autres opérateurs binaires d'affectation

Les opérateurs suivants ne sont que des racourcis de notation :
Opérateur équivalent Notation Priorité Ordre
+= x = x + y x += y 2 droite-gauche
-= x = x - y x -= y 2 droite-gauche
. *= x = x * y x *= y 2 droite-gauche
/= x = x / y x /= y 2 droite-gauche
%= x = x % y x %= y 2 droite-gauche
>>= x = x >> y x >>= y 2 droite-gauche
<<= x = x << y x <<= y 2 droite-gauche
&= x = x & y x &= y 2 droite-gauche
|= x = x | y x |= y 2 droite-gauche
^= x = x & y x |= y 2 droite-gauche

2.2.7 Les autres opérateurs unaires d'affectation

++ x = x + 1 x++ ou ++x 14 droite-gauche
-- x = x - 1 x-- ou --x 14 droite-gauche
Les opérateurs d'incrément et de décrément sont en position de préfixe ou de suffixe : l'expression y = x++ est le raccourci pour y = x; x = x + 1; et l'expression y = ++x est le raccourci pour x = x + 1; y = x;. Ces opérateurs produisent des effets de bord. Un effets de bord est la modification d'une opérande lors de l'évaluation d'une l'expression; dans l'exemple ci-dessus, la variable x subit une modification pendant l'affectation de la variable y.

2.2.8 Autres opérateurs

L'opérateur conditionnel

 Voici, enfin, l'opérateur ternaire (le seul dans C).

?: opérateur conditionnel e ? x : y 3 droite-gauche
Cette expression est une sorte de si alors sinon sous forme d'expression: si la condition e est vraie alors cette expression vaut x sinon elle vaut y .

Exemple: a = (v == 2) ? 1 : 2; affecte la variable a à la valeur 1 si v vaut 2, sinon affecte la variable a à la valeur 2.

L'opérateur séquentiel

, opérateur séquentiel e1, e2 1 droite-gauche
Cet opérateur permet de regrouper plusieurs expressions en une seule : l'évaluation de l'expression e1, e2 consiste en l'évaluation successives (dans l'ordre) des expressions e1 puis de e2. L'expression e1, e2 possède le type et la valeur de e2.

L'opérateur de dimension

Cet opérateur donne l'occupation mémoire (en octets) d'une variable ou d'un type de donné.

sizeof opérateur de dimension sizeof(e)[*] 14 droite-gauche

Exemple.

La valeur de l'expression sizeof(c) est 1 si c est une variable de type char; l'expression sizeof(char) donne également la valeur 1.

L'opérateur d'adressage

L'opérateur d'adressage[*] & donne l'adresse d'une variable ou d'une expression qui est une lvalue.

& opérateur d'adressage &x 14 droite-gauche

L'opérateur de conversion (cast)

 Cet opérateur permet de convertir explicitement le type d'une donnée en un autre type. Nous dans la section 2.3 les converions implicites que fait le compilatateur C.
(type) opérateur de conversion (long int)c 14 droite-gauche

L'opérateur de paranthésage

L'opérateur de parathèsage () permet de définir l'ordre d'évaluation d'une expression. C'est l'opérateur que l'on utilise traditionellement.

C'est également ce même opérateur qui est utilisé pour encapsuler les paramètres des fonctions. Même lorsqu'une fonction n'a pas d'arguments, ces paranthèses sont requises.

() paranthésage () 15 gauche-droite

Exemple


   
2|c|Définition de fonction  
   


int fonction2(char c, int i)
{
....
}





int fonction0(void)
{
....
}



   
2|c|Appel de fonction  
   


{
....
i = fonction2('c', 235);
....
}





{
....
i = fonction0();           
....
}



   

L'opérateur de selection

 Ces opérateurs . et -> servent à selectionner des composants de données structurées. Nous rencontrerons ces opérateurs plus loin dans ce doucument (voir chapitre 6).
. opérateur de selection x.info 15 gauche-droite
-> opérateur de selection x->info 15 gauche-droite
[] opérateur de selection x[3] 15 gauche-droite

2.3 Conversion de types

  Le problème de la conversion des types se pose lorsqu'une expression est composée de données de nature différentes. Par exemple, quel sens donner à une addition d'un entier et d'un nombre flottant ? Que se passe-t-il lorsqu'on affecte un variable de type entier à une valeur de type caractère ou flottant. La langage de C définit précisément quelles sont les types de données compatibles et quel type de conversion est effectuée.

2.3.1 Les conversions implicites

Les conversion implicites sont celles faites automatiquement par un compilateur C lors de l'évaluation d'une expression (et donc également d'une affectation). Comme nous le verrons plus loin, il y a également conversion implicite lors de l'appel de fonction (voir chapitre 4).

Cas de l'évaluation d'une expression

Lorsqu'il est nécessaire de procéder à des conversions, le compilteur C effectue tout d'abord les conversions puis évalue l'expression. Les règles de conversion suivantes s'appliquent dans l'ordre:

Cas de l'affectation.

Lors d'une affectation, le type de l'expression membre droit est converti (si nécessaire) en le type de l'expression en membre gauche. Par exemple, les char sont convertis en int.

Mais que se passe-t-il lorsqu'on affecte une expression plus ``longue'' à une expression plus ``courte'' ?

 
int i;
char c;

c = i;

La valeur affectée à la variable c sera tronquée des bits de poids forts. Le conversion d'un float en un int, tronque la partie fractionnaire; mais selon l'implantation, la conversion d'un double en float sera arrondie ou tronquée.

2.3.2 Les conversions explicites

Outre les conversion implicites, le programmeur peut effectuer des conversions à la demande grâce à l'opérateur de converiosn de type que l'on a déjà rencontré en 2.2.8. L'expression (int) 1.225 convertit le réel de type double en un entier. il en découle évidemment une perte de précision selon les règles que nous avons précisées plus haut; pour cet exemple, la conversion de (int) 1.225 donne comme résultat la valeur entière 1.

2.4 Récapitulatif

Opérateur Nom   Priorité Ordre
[] elt de tableau   15 gauche-droite
() paranthésage   15 gauche-droite
. selection   15 gauche-droite
-> selection   15 gauche-droite
& adressage   15 gauche-droite
sizeof dimension   14 droite-gauche
(type) conversion   14 droite-gauche
! (unaire) NON   14 droite-gauche
~ (unaire) NON bit à bit   14 droite-gauche
++ incrément   14 droite-gauche
-- décrément   14 droite-gauche
* multiplication   13 gauche-droite
/ division   13 gauche-droite
% modulo   13 gauche-droite
+ Addition   12 gauche-droite
- soustraction   12 gauche-droite
>> décalage à droite   11 droite-gauche
<< décalage à gauche   11 droite-gauche
<= test d'inférieur ou égal   10 gauche-droite
>= test de supérieur ou égal   10 gauche-droite
<= test d'inférieur strict   10 gauche-droite
>= test de supérieur strict   10 gauche-droite
== test d'égalité   9 gauche-droite
!= test de non-égalité   9 gauche-droite
& ET bit à bit   8 gauche-droite
^ OU exclisif bit à bit   7 gauche-droite
| OU bit à bit   6 gauche-droite
&& ET   5 gauche-droite
|| OU   4 gauche-droite
?: opérateur conditionnel   3 droite-gauche
= Affectation   2 droite-gauche
+= Affectation   2 droite-gauche
-= Affectation   2 droite-gauche
. *= Affectation   2 droite-gauche
/= Affectation   2 droite-gauche
%= Affectation   2 droite-gauche
>>= Affectation   2 droite-gauche
<<= Affectation   2 droite-gauche
&= Affectation   2 droite-gauche
|= Affectation   2 droite-gauche
^= Affectation   2 droite-gauche
, séquentiel   1 droite-gauche


next up previous contents index
Next: 3 Structures de contrôle Up: Le langage C Previous: 1 Eléments de base

Touraivane
9/21/1998