Un identificateur correspond à des mots-clés utilisés pour spécifier ou donner un sens (i.e pouvoir comprendre le rôle uniquement via l’identificateur pour lire un programme plus rapidement) à des variables, des fonctions ou actions, des types ou des structures. Les identificateurs sont construits de la manière suivante:
_
Le principe d’une variable part de la volonté de stocker en mémoire des données, données que l’on peut retrouver facilement via leur identificateur. Étant donné que ces données peuvent être modifiées par le programme, elles ne sont pas constantes au cours du temps d’où le terme de variable. Bien entendu, les données peuvent être de différente nature: nombres, suite de nombres, texte, images… Ainsi sont définis les types qui permettent de catégoriser les différentes variables. Et une variable d’un type spécifique ne peut contenir que des données du même type. De même, certaines opérations sont valides sur un type donné mais pas sur d’autres. Au final une variable est un élément qui:
Avant d’utiliser une variable il faut la déclarer, c’est à dire spécifier son type et son identificateur.
Le type entier permet de représenter un nombre entier positif ou négatif. En C
, le type int
code des entiers signés sur 32 bits (4 octets). Par conséquent les entiers que l’on peut coder avec ce type int
appartiennent à l’intervalle [-2^31, 2^31^-1]
.
D’autres types existent pour représenter les entiers:
unsigned int
sur 4 octets qui représente des entiers positifs ou nuls [0, 2^32-1],short
sur 2 octets qui représente des entiers signés [-2^15^, 2^15^-1],unsigned short
sur 2 octets qui représente des entiers positifs ou nuls [0, 2^16-1],long
sur 8 octets qui représente des entiers signés [-2^63^, 2^63^-1].unsigned long
sur 8 octets qui représente des entiers positifs ou nuls [0, 2^64-1].Ceci implique par exemple que:
Sur ces types entiers, un certain nombre d’opérations existent:
Et bien entendu il est possible de comparer deux entiers ensemble avec les opérateurs de comparaison ==
(égalité), !=
(différence), <
, >
, <=
, >=
Le type bool
permet de représenter un booléen (deux états VRAI
ou FAUX
). En C
ce type n’existe pas réellement (à savoir un type qui prend 1 bit de mémoire). Il existe un type bool
défini depuis 1999 mais il s’agit en fait d’un entier codé sur 1 octet qui correspond à false
lorsqu’il vaut 0
et true
lorsqu’il vaut 1 (en fait toute valeur différente de 0
est considérée comme étant true
).
Pour les booléens, il existe bien évidemment les opérateurs logiques: &&
pour le ET-logique, ||
pour le OU-logique et !
pour le complément.
Le type réel permet de représenter un nombre réel quelque soit sa représentation. En C
la représentation interne est forcément scientifique (i.e. comme 0.5e^-4^) et se base sur la norme IEEE754 que nous ne détaillerons pas ici. Deux types permettent de représenter les réels: les réels simple précision float
codés sur 4 octets et les réels double précision double
codés sur 8 octets.
Les mêmes opérateurs arithmétiques et de comparaisons que pour les entiers existent sauf %
, <<
, >>
qui n’ont pas de sens sur des réels.
Le type réel permet de représenter n’importe quel caractère que l’on peut afficher (lettres, chiffres, signes de ponctuation…). En C
, un caractère est codé sur un octet. Chaque caractère est en fait représenté par un entier (signé ou non, cela dépend de l’architecture) en se basant sur la table ASCII étendue. Pour représenter la lettre a
, on utilise la syntaxe suivante: 'a'
. Vous utiliserez tout au long de l’année un certain nombre de caractère spéciaux: '\t'
(tabulation), '\n'
retour à la ligne…
L’utilisation de la table ASCII implique que ça n’est pas le symbole du caractère qui est stocké en mémoire mais son code ASCII qui est un entier. Du coup, il est possible de faire les opérations suivantes:
Tous les autres types dérivent de ces types de bases, ils seront vus plus tard (pour les tableaux) et au semestre 6 (pour les structures cartésiennes).
Après le stockage des données (section précédente), leur traitement se fait via des expressions comme par exemple effectuer la somme de variables ou tester si une variable entière est plus petite qu’un autre. On définit ainsi des expressions numériques et des expressions booléennes.
Par exemple en C
:
Ainsi, on remarque qu’une expression est constituée d’opérateurs, de sous-expressions et de sous expressions de base (variable ou constante).
En C
, une expression peut être (entre autres):
En C
, une affectation s’écrit de la manière suivante:
L’affectation est toujours construite de la manière suivante:
l-value
)r-value
)Ainsi la syntaxe 13 = i
n’est pas possible en C
car 13 n’est pas une l-value
(c’est une constante). Au niveau du fonctionnement, la valeur de droite est calculée (évaluée) et affectée à la variable de gauche. En C
, la valeur de l’expression-affectation est la valeur calculée à droite. Par exemple x = (y = 8) + 1
fait que x
vaut 9 et que la valeur de toute l’expression est également 9.
Il existe également des affectations qui utilisent un opérateur que l’on rencontre très fréquemment (on parle d’assignements composés):
Une constante est, comme son nom l’indique, une valeur qui ne change pas au cours de l’exécution d’un programme. C’est une fonctionnalité intéressante puisqu’elle permet d’écrire du code évolutif que l’on peut paramétrer.
En C
il y a plusieurs façons de définir une constante, nous en verrons deux.
La première syntaxe pour définir une constante est la suivante:
Cette syntaxe permet de faire un alias (i.e. raccourci) que le compilateur va utiliser pour remplacer dans la suite du programme toutes les occurrences de CONSTANTE
par valeur. Il est important de remarquer qu’il n’y a pas de ;
final. Cette syntaxe comporte deux inconvénients:
valeur
n’a pas de type, ce qui peut poser problème dans certains cas où des opérateurs différents suivant le type manipulé.Voici un exemple qui montre les limites de #define
:
Ici, le compilateur en faisant la substitution génère l’expression int z = 3 * X + Y;
. On peut corriger cette erreur en écrivant #define N ( (x) + (y) )
.
Cette syntaxe permet d’éviter les inconvénients mentionnés précédemment: l’absence de type et l’absence d’affectation. La syntaxe est proche de la déclaration d’une variable:
L’inconvénient principal de cette approche est que la constante est en mémoire et peut donc être involontairement modifiée (via des débordements mémoire par exemple).
Les deux approches sont valables, chacune est utilisable. Il faut juste être conscient de leurs limites qui peuvent créer des bogues dans vos programmes.
Une instruction est une ligne élémentaire d’un programme C
. Les instructions peuvent réaliser un calcul simple, affecter des variables… Les instructions vues dans ce cours seront:
En C
, une instruction est également une expression suivie de ;
(point-virgule). Par exemple:
L’instruction composée ou bloc est définie en C
par un groupe d’instructions qui sont encadrées par des accolades {}
. Un bloc présente plusieurs intérêts:
L’instruction conditionnelle est une instruction composée dont certaines instructions ne sont exécutées que dans certaines conditions. La syntaxe en C
est la suivante:
Voici quelques exemples en C
:
Soient les deux fragments de programme ci-dessous, quelles sont les valeurs de t
et de x
?
Cette deuxième instruction est fortement déconseillée (très peu d’avantage et source de nombres de bogues). Pour éviter les erreurs liés à la confusion entre les deux opérateurs, il est possible d’utiliser les Yoda-conditions, à savoir (valeur == variable)
. Si par inadvertance vous écrivez, if (5 = count)
, le compilateur génère une erreur puisque 5
n’est pas une l-value
et ne peut donc pas recevoir d’affectation.
L’objectif de cette instruction est simple: automatiser l’écriture de certaines instructions répétitives plutôt que de les écrire manuellement. On parler souvent de boucle puisqu’il s’agit d’une partie du programme qui est exécutée plusieurs fois.
La syntaxe classique est:
Le déroulement d’une boucle for
est le suivant:
cpt
est initialisé avec la valeur inf
cpt <= sup
est évaluée. Si elle vaut false
, on sort de la boucle (.i.e du bloc entre accolades)true
) les instructions du bloc sont exécutées.cpt = cpt + inc
est ensuite exécutée…cpt <= sup
est de nouveau évaluée et ainsi de suite.La syntaxe classique en C
est:
Le déroulement d’une boucle while
est le suivant: tant que expression est évalué à true
, le bloc d’instructions est exécuté. Ceci signifie, entre autres, que si la condition est initialement fausse, le bloc d’instructions n’est jamais exécuté.
Voici quelques exemples en C
:
La syntaxe classique est:
Le déroulement d’une boucle do-while
est le suivant: le bloc d’instructions est exécuté une fois, puis l’expression est évaluée. Si elle vraie, on boucle, sinon on sort de la boucle. Contrairement à la boucle while
même si expression est à false
, les instructions du bloc sont exécutées au moins une fois.