1.6 Les constantesUne constante est une valeur qui apparaît littéralement dans
le code source d'un programme, le type de la constante étant déterminé par la
façon dont la constante est écrite. Les constantes peuvent être de 4
types : entier, flottant (nombre réel), caractère, énumération. Ces
constantes vont être utilisées, par exemple, pour initialiser une variable.
1.6.1 Les constantes entièresUne constante entière peut être représentée de 3 manières
différentes suivant la base dans laquelle elle est écrite :
- décimale : par
exemple, 0 et 2437348 sont des constantes entières
décimales.
- octale : la
représentation octale d'un entier correspond à sa décomposition en
base 8. Les constantes octales doivent commencer par un zéro. Par
exemple, les représentations octales des entiers 0 et 255 sont
respectivement 00 et 0377.
- hexadécimale :
la représentation hexadécimale d'un entier correspond à sa décomposition
en base 16. Les lettres de a
à f sont utilisées pour
représenter les nombres de 10 à 15. Les constantes hexadécimales doivent
commencer par 0x ou 0X. Par exemple, les représentations
hexadécimales de 14 et 255 sont respectivement 0xe et 0xff.
Par défaut, une constante décimale est représentée avec le
format interne le plus court permettant de la représenter parmi les formats des
types int, long int et unsigned long int tandis qu'une constante octale ou
hexadécimale est représentée avec le format interne le plus court permettant
encore de la représenter parmi les formats des types int, unsigned
int, long int et unsigned long int.
On peut cependant spécifier explicitement le format d'une constante entière en
la suffixant par u ou U pour indiquer qu'elle est non signée, ou
en la suffixant par l ou L pour indiquer qu'elle est de type long. Par exemple :
constante
| Type
|
|
1234
| Int
|
02322
| int /* octal */
|
0x4D2
| int /* hexadécimal */
|
123456789L
| Long
|
1234U
| unsigned int
|
123456789UL
| unsigned long int
|
1.6.2 Les constantes réellesLes constantes réelles sont représentées par la notation
classique par mantisse et exposant. L'exposant est introduit par la lettre e ou E ;
il s'agit d'un nombre décimal éventuellement signé.
Par défaut, une constante réelle est représentée avec le format du type double. On peut cependant influer sur la
représentation interne de la constante en lui ajoutant un des suffixes f (indifféremment F) ou l
(indifféremment L). Les suffixes
f et F forcent la représentation de la constante sous forme d'un
float, les suffixes l et L
forcent la représentation sous forme d'un long
double. Par exemple :
constante
| type
|
|
12.34
| double
|
12.3e-4
| double
|
12.34F
| float
|
12.34L
| long double
|
1.6.3 Les constantes caractèresPour désigner un caractère imprimable, il suffit de le
mettre entre apostrophes (par ex. 'A'
ou '$'). Les seuls caractères
imprimables qu'on ne peut pas représenter de cette façon sont l'antislash et
l'apostrophe, qui sont respectivement désignés par \\ et '. Le
point d'interrogation et les guillemets peuvent aussi être désignés par les
notations \? et ". Les caractères non imprimables
peuvent être désignés par '\
code-octal' où
code-octal est le code en
octal du caractère. On peut aussi écrire '\x
code-hexa' où
code-hexa est le code en
hexadécimal du caractère. Par exemple, '\33'
et '\x1b' désignent le caractère
escape. Toutefois, les caractères non-imprimables les plus fréquents
disposent aussi d'une notation plus simple :
\n
| nouvelle ligne
| \r
| Retour chariot
|
\t
| tabulation horizontale
| \f
| saut de page
|
\v
| tabulation verticale
| \a
| Signal d'alerte
|
\b
| retour arrière
|
|
|
1.6.4 Les constantes chaînes de
caractèresUne chaîne de caractères est une suite de caractères
entourés par des guillemets. Par exemple,
"Ceci est une chaîne de caractères"
Une chaîne de caractères peut contenir des caractères non
imprimables, désignés par les représentations vues précédemment. Par exemple,
"ligne 1 \n ligne 2"
A l'intérieur d'une chaîne de caractères, le caractère " doit être désigné par ". Enfin, le caractère \ suivi d'un passage à la ligne est
ignoré. Cela permet de faire tenir de longues chaînes de caractères sur
plusieurs lignes. Par exemple,
"ceci est une longue longue longue longue longue longue longue longue \chaîne de caractères"
1.7 Les opérateurs1.7.1 L'affectationEn C, l'affectation est un opérateur à part entière. Elle
est symbolisée par le signe =.
Sa syntaxe est la suivante :
variable =
expressionLe terme de gauche de l'affectation peut être une variable
simple, un élément de tableau mais pas une constante. Cette expression a pour
effet d'évaluer
expression et d'affecter la valeur obtenue à
variable.
De plus, cette expression possède une valeur, qui est celle
expression.
Ainsi, l'expression i = 5 vaut
5.
L'affectation effectue une
conversion de type implicite : la
valeur de l'expression(terme de droite) est convertie dans le type du terme de
gauche.Par exemple, le programme suivant
main(){ int i, j = 2; float x = 2.5; i = j + x; x = x + i; printf("\n %f \n",x);}
imprime pour x
la valeur 6.5 (et non 7), car dans l'instruction i = j + x;, l'expression j
+ x a été convertie en entier.
1.7.2 Les opérateurs arithmétiquesLes opérateurs arithmétiques
classiques sont l'opérateur unaire -
(changement de signe) ainsi que les opérateurs binaires
+
| addition
|
-
| soustraction
|
*
| multiplication
|
/
| division
|
%
| reste de la division (modulo)
|
Ces opérateurs agissent de la façon attendue sur les entiers
comme sur les flottants. Leurs seules spécificités sont les suivantes :
- Contrairement à d'autres
langages, le C ne dispose que de la notation / pour désigner à la fois la division entière et la
division entre flottants. Si les deux opérandes sont de type entier,
l'opérateur / produira une
division entière (quotient de la division). Par contre, il délivrera une
valeur flottante dès que l'un des opérandes est un flottant. Par exemple,
· float x;
· x = 3 / 2;
affecte à x
la valeur 1. Par contre
x = 3 / 2.;
affecte à x
la valeur 1.5.
- L'opérateur % ne s'applique qu'à des opérandes de
type entier. Si l'un des deux opérandes est négatif, le signe du reste
dépend de l'implémentation, mais il est en général le même que celui du
dividende.
Notons enfin qu'il n'y a pas en C d'opérateur
effectuant l'élévation à la puissance. De façon générale, il faut utiliser la
fonction pow(x,y) de la
librairie math.h pour calculer
xy.
1.7.3 Les opérateurs relationnels >
| strictement supérieur
|
>=
| supérieur ou égal
|
<
| strictement inférieur
|
<=
| inférieur ou égal
|
==
| égal
|
!=
| différent
|
Leur syntaxe est
expression-1 op expression-2 Les deux expressions sont évaluées puis comparées. La valeur
rendue est de type int (il n'y a
pas de type booléen en C); elle vaut 1 si la condition est vraie,
et 0 sinon.
Attention à ne pas confondre l'opérateur de test d'égalité == avec l'opérateur d'affection =. Ainsi, le programme
main(){ int a = 0; int b = 1; if (a = b) printf("\n a et b sont egaux \n"); else printf("\n a et b sont differents \n");}
imprime à l'écran a et b
sont egaux !
1.7.4 Les opérateurs logiques booléens &&
| et logique
|
||
| ou logique
|
!
| négation logique
|
Comme pour les opérateurs de comparaison, la valeur retournée par ces
opérateurs est un int qui
vaut 1 si la condition est vraie et 0 sinon.
Dans une expression de type
expression-1 op-1 expression-2 op-2 ...expression-nl'évaluation se fait de gauche à droite et s'arrête dès que
le résultat final est déterminé. Par exemple dans
int i;int p[10]; if ((i >= 0) && (i <= 9) && !(p
== 0))...
la dernière clause ne sera pas évaluée si i n'est pas entre 0 et 9.
1.7.5 Les opérateurs logiques bit à bit
Les six opérateurs suivants
permettent de manipuler des entiers au niveau du bit. Ils s'appliquent aux
entiers de toute longueur (short,
int ou long), signés ou non.
&
| et
|
| |
| ou inclusif
|
^
| ou exclusif
|
| ~
| complément à 1
|
<<
| décalage à gauche
|
| >>
| décalage à droite
|
En pratique, les opérateurs &,
| et ~ consistent à appliquer bit à bit les opérations suivantes
L'opérateur unaire ~ change la valeur de chaque bit d'un
entier. Le décalage à droite et à gauche effectuent respectivement une
multiplication et une division par une puissance de 2. Notons que ces décalages
ne sont pas des décalages circulaires (ce qui dépasse disparaît).
Considérons par exemple les entiers a=77
et b=23 de type unsigned char ([i]i.e. 8 bits). En
base 2 il s'écrivent respectivement 01001101 et 00010111.
| valeur
|
expression
| binaire
| décimale
|
a
| 01001101
| 77
|
b
| 00010111
| 23
|
a & b
| 00000101
| 5
|
a | b
| 01011111
| 95
|
a ^ b
| 01011010
| 90
|
~a
| 10110010
| 178
|
b << 2
| 01011100
| 92
| multiplication par 4
|
b << 5
| 11100000
| 112
| Ce qui dépasse disparaît
|
b >> 1
| 00001011
| 11
| division entière par 2
|
1.7.6 Les opérateurs d'affectation
composéeLes opérateurs d'affectation composée sont
+= -=
*= /= %= &= ^=
|= <<= >>=
Pour tout opérateur
op, l'expression
expression-1 op=
expression-2 est équivalente à
expression-1 =
expression-1 op expression-2 Toutefois, avec l'affection composée,
expression-1n'est évaluée qu'une seule fois.
1.7.7 Les opérateurs d'incrémentation et
de décrémentationLes opérateurs d'incrémentation ++ et de décrémentation --
s'utilisent aussi bien en suffixe (i++)
qu'en préfixe (++i). Dans les
deux cas la variable i sera
incrémentée, toutefois dans la notation suffixe la valeur retournée sera
l'ancienne valeur de i alors que
dans la notation préfixe se sera la nouvelle. Par exemple,
int a = 3, b, c; b = ++a; /* a et b valent 4 */c = b++; /* c vaut 4 et b vaut 5 */
1.7.8 L'opérateur virguleUne expression peut être constituée d'une suite
d'expressions séparées par des virgules :
expression-1,
expression-2, ... ,
expression-n Cette expression est alors évaluée de gauche à droite. Sa valeur sera la valeur
de l'expression de droite. Par exemple, le programme
main(){ int a, b; b = ((a = 3), (a + 2)); printf("\n b = %d \n",b);}
imprime b = 5.
La virgule séparant les arguments d'une fonction ou les
déclarations de variables n'est pas l'opérateur virgule. En particulier
l'évaluation de gauche à droite n'est pas garantie. Par exemple l'instruction
composée
{int a=1; printf("\%d \%d",++a,a);}
1.7.9 L'opérateur conditionnel ternaireL'opérateur conditionnel
? est un opérateur ternaire. Sa syntaxe est la suivante :
condition ?
expression-1 :
expression-2Cette expression est égale à
expression-1 si
conditionest satisfaite, et à
expression-2 sinon. Par exemple, l'expression
x >= 0 ? x : -x
correspond à la valeur absolue d'un nombre. De même
l'instruction
m = ((a > b) ? a : b);
affecte à m
le maximum de a et de b.
1.7.10 L'opérateur de conversion de typeL'opérateur de conversion de type, appelé
cast,
permet de modifier explicitement le type d'un objet. On écrit
(
type)
objet Par exemple,
main(){ int i = 3, j = 2; printf("%f \n",(float)i/j);}
retourne la valeur 1.5.
1.7.11 L'opérateur adresseL'opérateur d'adresse &
appliqué à une variable retourne l'adresse-mémoire de cette variable. La
syntaxe est
&
objet1.7.12 Règles de priorité des opérateursLe tableau suivant classe les
opérateurs par ordres de priorité décroissants. Les opérateurs placés sur une
même ligne ont même priorité. Si dans une expression figurent plusieurs
opérateurs de même priorité, l'ordre d'évaluation est définie par la flèche de
la seconde colonne du tableau. On préferera toutefois mettre des parenthèses en
cas de doute...
Opérateurs
|
|
() [] -> .
| ®
|
! ~ ++ -- -(unaire) (type) *(indirection) &(adresse) sizeof
| ¬
|
* / %
| ®
|
+ -(binaire)
| ®
|
<< >>
| ®
|
< <= > >=
| ®
|
== !=
| ®
|
&(et bit-à-bit)
| ®
|
^
| ®
|
|
| ®
|
&&
| ®
|
||
| ®
|
? :
| ¬
|
= += -= *= /= %= &= ^= |= <<= >>=
| ¬
|
,
| ®
|
Table 1.4: Règles de priorité des opérateurs
Par exemple, les opérateurs logiques bit-à-bit sont moins
prioritaires que les opérateurs relationnels. Cela implique que dans des tests
sur les bits, il faut parenthéser les expressions. Par exemple, il faut écrire if ((x ^ y) != 0)