Académique Documents
Professionnel Documents
Culture Documents
Objectifs
• Connaître les différents types d’opérateur et les manipuler
• Connaître les différents types d’expressions et les manipuler
Eléments de contenu
• Les opérateurs arithmétiques
• La conversion implicite de type dans les expressions
• Les opérateurs relationnels
• Les opérateurs logiques
• L’opérateur d’affectation simple
• Les opérateurs d’incrémentations et de décrémentation
• Les opérateurs de manipulations de bits
• Les opérateurs d’affectation élargie
• L’opérateur conditionnel
• Les conversions explicites
• L’opérateur de “cast”
• L’opérateur séquentiel
• L’opérateur sizeof
VI.1. LES OPERATEURS ARITHMETIQUES
VI.1.a. Leur rôle
On trouve en C :
• 5 opérateurs “binaires“ (c’est à dire qui portent sur deux opérandes)
• 2 opérateurs unaires qui portent sur un seul opérande.
Binaire + somme
- différence A l’exception de l’opérateur “%“ qui ne peut porter
* produits
que sur des entiers, ces opérateurs peuvent
/ quotient
s’appliquer à tous les types numériques. Cela
% reste de division
(modulo) signifie qu’un même symbole tel que ”*” définit en
Unaire - opposé
fait plusieurs opérations différentes suivant le type
+ Identité
des quantités sur lesquelles il porte.
Les opérateurs binaires ne sont, à priori, définie que pour des opérandes de même type et ils
fournissent un résultat de ce même type. Ce dernier point mérite un peu d’attention. En effet, si ‘on
s’attend effectivement à ce que la somme de deux entiers soit un entier, les choses sont moins
évidentes pour l’opérateur quotient (“/”). Ainsi par exemple, si 5/2 est le quotient de deux valeurs
doubles, et à ce titre fournit bien le résultat 2.5 qui est aussi (de type double). Par contre, si 5/2 est le
quotient de deux valeurs de type int et le résultat est de type int, a savoir ici 2.
Remarque
Il n’existe pas d’opérateur d’élévation à la puissance (^), il est nécessaire de faire appel soit â des
produits successifs, soit à la fonction power de la bibliothèque.
a+b*c a+(b* c)
a*b+c%d (a*b)+(c%d)
-c % d (-c)%d
-a/-b+c ((-a)/(-b))+c
VI.2. LES CONVERSIONS IMPLICITES DE TYPE DANS LES EXPRESSIONS
A l’opposé de ce qui se passe dans un langage comme Pascal, Le langage C est très tolérant vis a
vis du mélange des types dans les expressions.
Ainsi, par exemple, si n est le type int, et x de type double, une expression telle que : n+x
sera acceptée par le compilateur. Elle conduira à la mise en place d’instructions réalisant :
• la conversion de n en double. Cette opération a un sens et est toujours possible.
• l’addition des deux valeurs de type double. Le résultat sera lui aussi de type double.
On dit qu’il y a eu mise en place de “conversions implicites” puisque celles-ci n’ont pas été
explicitées au sein des instructions.
D’une manière générale, on peu dire que si un opérateur porte sur deux opérandes de type
différents, il y a en quelque sorte, conversion du type “le plus faible’ dans le type “le plus fort”. Ainsi,
dans notre exemple double était plus fort que int.
Une grande originalité du C est d’étendre ces facilités de conversions aux types caractères. Cette
fois cependant le mécanisme sera un peu diffèrent car tout opérande de type char apparaissant
dans une expression sera systématiquement converti en int avant d’intervenir dans les calculs.
Il est à noter aussi que tous les calculs flottants ne s’effectuent que sur des valeurs de type double.
Pour ce faire tout opérande de type float est systématiquement converti en double.
VI.2.a. Exemples de conversions implicites sur des types numériques
Supposons que nous avons effectué les déclarations suivantes :
Int n, p
long q, r
float x
double z
Voici trois exemples d’expressions et la manière dont elles vont être évaluées :
• n + q : La valeur de n est convertie en long avant d’être ajoutée à celle de q. Le résultat est de
type long
• q + n *p : Le produit n * p est évalué en int puis le résultat est converti en long pour être ajouté à
la valeur de q. Le résultat est de type long
• x * n : Les valeurs de x et de n sont converties en double. Le résultat est de type double. Bien
entendu, rien n’empêchera ce résultat d’être assigné à une variable de type float (moyennant
une conversion supplémentaire).
VI.2.b. Exemples de conversions implicites de char et int
Supposons que nous avons effectué les déclarations suivantes :
int n
char cl , c2
Voici, à nouveau quelques exemples d’expressions et la manière dont elles sont évaluées :
• C1 + 1 : La valeur de cl est d’abord convertie en int. Cette conversion revient en fait à considérer que les 8
bits occupés par cl forment une valeur entière codée de la même manière que les entiers (mais sur 8 bits
au lieu de 16). Il faudra toutefois distinguer deux cas suivant que cl possède l’attribut signed ou unsigned :
- si cl est unsigned la conversion revient effectivement à prendre la valeur du code ASCII du
caractère on obtiendra ainsi, une valeur entière comprise entre 0 et 255.
- si cl est signed, le premier des 8bits Sera interprété comme un bit de signe. On obtiendra ainsi une
valeur entière comprise entre -128 et 127.
au résultat de cette conversion, on ajoutera la valeur entière de 1.
• cl + n : Là encore, la valeur de cl sera convertie en int. Le résultat sera ajoutée la valeur n pour fournir une
valeur de type int.
• c2 - cl : Ici, bien que les deux opérandes soient de type char, il y aura néanmoins conversion préalable
des valeurs de cl et c2 on int avant que soit calculée la différence. Le résultat est de type int.
VI.2.c. Règles générales de conversion implicite
i) Conversions systématiques et conversion d’ajustement de type
Comme on a vu dans les exemples précédents, il faut distinguer les conversions qui ont lieu
systématiquement de celles qui ne sont réalisées qu’en cas de besoin par ”absorption” par un type plus fort.
Les conversions systématique se résument
char —> int
float —> double
Quant aux autres conversions, elles permettent de faire porter un opérateur sur des valeurs de même type.
Le type commun étant imposé par celui des opérandes ayant le type le plus fort. Voici le schéma
récapitulant ces règles. Les flèches horizontales correspondent à des conversions systématiques. Les flèches
verticales correspondent â des conversions d’ajustement de type.
char —> int —> long
ce qui, en C, a effectivement une signification, compte tenu de ce que les expressions a<b et c<d
sont, finalement, des quantités entières.
D’autre part, ces opérateurs relationnels sont moins prioritaires, que les opérateurs arithmétiques.
Cela permet souvent d’éviter certaines parenthèses dans des expressions. Ainsi :
x + y < a + 2 est équivalent à (x + y ) < (a + 2)
VI.4. OPERATEURS LOGIQUES
C dispose de trois opérateurs logiques classiques
OPERATEUR SIGNIFICATION
&& et
II Ou (inclusif)
! négation
Par exemple :
• (a < b) && (c < d ) : prend la valeur 1 (vrai) si les deux expressions a <b et c < d sont toutes deux
vrais(de valeur 1), la valeur 0 (faux) dans le cas contraire.
• (a < b) II ( c < d) : prend la valeur 1 (vrai) si l’une au moins des deux expressions a < b et c< d est
vraie (de valeur 1), la valeur 0 (faux) dans le cas contraire.
• !(a < b) : prend la valeur 1 (vrai) si la condition a < b est fausse (de valeur 0 ) et la valeur (faux)
dans le cas contraire. Cette expression est équivalente à : a >= b.
Notez bien que, ne disposant pas de type logique, C représente vrai par 1 et faux par 0 c’est
pourquoi ces opérateurs produisent un résultat numérique (de type int).
De plus, on pourrait s’attendre à ce que les opérandes de ces opérateurs ne puissent être que des
expressions prenant soit la valeur 0, soit la valeur1. En fait ces opérateurs acceptent n’importe quel
opérande numérique, y compris les types flottants, avec les règles de conversion implicite déjà
rencontrées. Leur signification reste celle évoquée ci-dessus, à condition de considérer que :
• 0 correspond à faux,
• toute valeur non nulle correspond à vrai.
Ainsi en C, si n et p sont des entiers, des expressions telles que : n && p n II p !n
sont acceptées par le compilateur. Notez que l’on rencontre fréquemment if( !n)
pour dire: if (n == 0)
L’opérateur (!) a une priorité supérieure à celle de tous les opérateurs arithmétiques binaires et aux
opérateurs relationnels. Ainsi, pour écrire la condition contraire de : a == b il est nécessaire d’utiliser
des parenthèses en écrivant : !(a== b).
En effet, l’expression !a == b serait interprétée comme : (!a) == b
L’opérateur II est mois prioritaire que &&. Tous deux sont de priorité inférieure aux opérateurs
arithmétiques ou relationnels. Ainsi, l’expression : a < b && c < d est équivalente à : (a < b) && (c < d)
Enfin, les deux opérateur && et II jouissent en C d’une propriété intéressante : leur second opérande
(celui qui figure à droite de l’opérateur) n’est évaluée que si la connaissance de sa valeur est
indispensable pour décider si l’expression correspondante est vraie ou fausse. Par exemple, dans une
expression telle que : a < b && c < d on commence par évaluer a < b. si le résultat est faux ; il est
inutile d’évaluer c < d puisque, de toutes façons, l’expression complète aura la valeur faux (0).
VI.5. L’OPERATEUR D’AFFECTATION SIMPLE
VI.5.a. Introduction
Nous avons déjà eu l’occasion de remarquer que i = 5 était un expression qui :
• réalisait un action : l’affectation de la valeur 5 à i
• possédait une valeur : celle de i après affectation, c’est à dire 5
Cet opérateur d’affectation (=) peut faire intervenir d’autres expressions, comme dans : c = b + 3
La faible priorité de cet opérateur = ( elle est inférieure à celle de tous les opérateurs arithmétiques et
de comparaison ) fait qu’il y a d’abord évaluation de l’expression b + 3. La valeur ainsi obtenue est
ensuite affectée à c.
Par contre, il n’est pas possible de faire apparaître une expression comme premier opérande de cet
opérateur =. Ainsi, l’expression c + 5 = x n’aurait pas de sens
VI.5.b. Notion de ‘‘IvaIue”
Nous voyons donc que cet opérateur d’affectation impose des restrictions sur son premier opérande.
En effet ce dernier doit être une “référence” a un“ emplacement mémoire” dont on pourra
effectivement modifier la valeur.
Dans Les autres langages, on désigne souvent une telle référence par le nom de “variable” ; on précise
généralement que ce terme, recouvre par exemple les éléments d’un tableaux ou les composantes
d’une structure.
En langage C, la syntaxe du langage est tel que cette notion de variable n’est pas assez précise. Il faut
introduire un mot nouveau : la IvaIue. Ce terme désigne une “valeur à gauche”, c’est à dire tout ce qui
peut apparaître à gauche d’un opérateur d’affectation.
VI.5.c. Associativité
Contrairement à tous les opérateurs que nous avons rencontrés jusqu’ici, cet opérateur d’affectation
possède une associativité de “droite à gauche”. C’est ce qui permet à une expression telle que : i=j
= 5 d’évaluer d’abord l’expression j=5 avant d’en affecter la valeur (5) à la variable j. La valeur finale
de cette expression est celle de i après affectation, c’est à dire 5.
VI.6. LES OPERATEURS D’INCREMENTATION ET DE DECREMENTATION
VI.6.a. Présentation
Dans des programmes écrits dans un langage autre que C, on rencontre souvent des expressions (ou
des instructions) telles que i = i + 1, n = n – 1 qui “incrémente” ou qui “décrémente” de 1 la valeur
d’une“ variable” (ou plus généralement d’une “lvalue”).
En C ces actions peuvent être réalisées par des opérateurs unaires portant sur cette “lvalue”. Ainsi,
l’expression : ++i a pour effet l’incrémenter de 1 la valeur de i et sa valeur est celle de i après
incrémentation.
Notez bien que, comme pour l’affectation, nous avons une expression qui, non seulement a une
valeur, mais qui réalise aussi une action (incrémentation de i).
Il est important de voir que la valeur de cette expression est celle incrémentation. Ainsi, si la valeur de
i est 5, l’expression : n = ++i – 5 affectera à i la valeur de 6 et à n la valeur de 1.
Par contre, lorsque cet opérateur est placé après la “lvalue” sur laquelle il porte, la valeur de
l’expression correspondante est celle de la variable avant incrémentation. Ainsi, si la valeur de i est 5,
l’expression : n = i++ - 5 affectera à i la valeur de 6 et à n la valeur de 0 (car ici la valeur de
l’expression i++ est 5).
On dit que ++ est :
• un opérateur de pré-incrémentation lorsqu’il est placé à gauche de la “lvalue” sur laquelle il
porte.
• un opérateur de post-incrémentation lorsqu’il est placé à droite de la “lvalue” sur laquelle il porte.
Lorsque seul importe l’effet d’incrémentation d’une “lvalue”, cet opérateur peut être indifféremment
placé avant ou après. Ainsi, ces deux instructions sont équivalentes : i++ ; ++i ;
De la même manière, il existe un opérateur de décrémentation noté ‘’--’’ qui, suivant les ces, sera :
• un opérateur de pré-décrémentation lorsqu’il est placé à gauche de la “lvalue” sur laquelle il
porte.
• un opérateur de post-décrémentation lorsqu’il est placé à droite de la “lvalue” sur laquelle il porte.