« Langage C/Conditions » : différence entre les versions

Contenu supprimé Contenu ajouté
Mewtow (discussion | contributions)
Création du chapitre
 
Mewtow (discussion | contributions)
m ajout de la suite du chapitre
Ligne 78 :
 
Certains langages fournissent pour cela un type bien séparé pour stocker le résultat des opérations de comparaisons. La représentation des valeurs "vrai" et "faux" est ainsi gérée par le compilateur, et on peut travailler dans notre code en utilisant à la place des valeurs True (vrai en anglais) ou False (faux). Mais dans les premières versions du langage C, ce type spécial n'existe pas ! Il a donc fallu ruser et trouver une solution pour représenter les valeurs "vrai" et "faux". Pour cela, on a utilisé la méthode la plus simple : on utilise directement des nombres pour représenter ces deux valeurs. Ainsi, la valeur Faux est représentée par un nombre entier, tout comme la valeur Vrai.
 
Le langage C impose que :
*Faux soit représenté par un zéro ;
Ligne 110 ⟶ 111 :
 
Le résultat confirme bien ce que je vous ai dit ci-dessus : les résultats de ces conditions sont soit 0 si la comparaison effectuée est fausse, soit 1 si elle est vraie.
 
= Les opérateurs logiques =
 
Toutes ces comparaisons sont un peu faibles seules : il y a des choses qui ne sont pas possibles en utilisant une seule de ces comparaisons.
 
Par exemple, on ne peut pas vérifier si un nombre est dans un intervalle en une seule comparaison. Supposons que pour une raison quelconque, je veuille vérifier que le contenu d'une variable de type int est compris entre 0 et 1000, 0 et 1000 non inclus. Je ne peux pas vérifier cela avec une seule comparaison (ou alors il faut vraiment ruser). On peut vérifier que notre entier est inférieur à 1000 OU qu'il est supérieur à zéro, mais pas les deux en même temps. Il nous faudrait donc trouver un moyen de combiner plusieurs comparaisons entre elles pour résoudre ce problème. Eh bien rassurez-vous : le langage C fournit de quoi combiner plusieurs résultats de comparaisons, plusieurs booléens. Il fournit pour cela ce qu'on appelle des opérateurs booléens, aussi appelés des opérateurs logiques.
 
== Les opérateurs logiques de base ==
 
Il existe trois opérateurs logiques. L'opérateur ET, l'opérateur OU, et l'opérateur NON. Les opérateurs ET et OU vont permettre de combiner deux booléens. L'opérateur NON ne servira par contre pas à cela, comme vous allez le voir. Voyons plus en détail ces trois opérateurs.
 
=== L'opérateur ET ===
 
L'opérateur ET va manipuler deux booléens. Il va renvoyer "vrai" si les deux booléens sont vrais, et renverra faux sinon.
 
{|
|Premier booléen
|Second booléen
|Résultat
|-
|Faux
|Faux
|Faux
|-
|Faux
|Vrai
|Faux
|-
|Vrai
|Faux
|Faux
|-
|Vrai
|Vrai
|Vrai
|}
 
Il permet par exemple de vérifier que deux comparaisons sont vraies en même temps : il suffit d'appliquer un opérateur ET sur les booléens renvoyés par les deux comparaisons pour que notre opérateur ET nous dise si les deux comparaisons sont vraies en même temps.
 
Cet opérateur s'écrit &&. Il s'intercalera entre les deux comparaisons ou booléens à combiner.
 
Par exemple, reprenons l'exemple vu plus haut, avec l'intervalle. Si je veux combiner les comparaisons a > 0 et a < 1000, je devrais écrire ces deux comparaisons entièrement, et placer l'opérateur ET entre les deux. Ce qui fait que l'expression finale sera a > 0 && a < 1000.
 
=== L'opérateur OU ===
 
L'opérateur OU fonctionne exactement comme l'opérateur ET : il prend deux booléens et les combines pour former un résultat. La différence c'est que l'opérateur OU ne vérifie pas que les deux booléens vrais en même temps. À la place, il va vérifier si un seul des booléens qu'il manipule est vrai. Si c'est le cas, il renverra "vrai". Dans les autres cas, il renverra "Faux".
 
{|
|Premier booléen
|Second booléen
|Résultat
|-
|Faux
|Faux
|Faux
|-
|Faux
|Vrai
|Vrai
|-
|Vrai
|Faux
|Vrai
|-
|Vrai
|Vrai
|Vrai
|}
 
Cet opérateur s'écrit ||. Il s'intercalera entre les deux booléens ou les deux comparaisons à combiner.
 
Pour donner un exemple, supposons que je veuille savoir si un nombre est divisible par 3 ou par 5, ou les deux. Pour cela, je vais devoir utiliser deux comparaisons : une qui vérifie si notre nombre est divisible par 3, et une autre qui vérifie s’il est divisible par 5. Ces conditions sont a % 3 == 0 pour le test de divisibilité par 3, et a % 5 ==0 pour le test de divisibilité par 5. Il reste juste à combiner les deux tests avec l'opérateur ||, ce qui donne : ( a % 3 == 0 ) || ( a % 5 == 0 ). Vous remarquerez que j'ai placé des parenthèses pour plus de lisibilité.
 
=== L'opérateur NON ===
 
Cet opérateur est un peu spécial : il va manipuler un seul booléen, contrairement à ses confrères ET et OU. Son rôle est d'inverser ce dernier.
 
{|
|Booléen
|Résultat
|-
|Faux
|Vrai
|-
|Vrai
|Faux
|}
 
Cet opérateur se note ! . Son utilité ? Simplifier certaines expressions.
 
Par exemple, si je veux vérifier qu'un nombre n'est pas dans l'intervalle ] 0 , 1000 [, on peut utiliser l'opérateur NON intelligemment. Je sais vérifier qu'un nombre est dans cet intervalle : il me suffit d'écrire l'expression a > 0 && a < 1000, vu plus haut. Pour rappel, cette expression permet de vérifier qu'un nombre est dans cet intervalle. Pour vérifier la condition inverse, à savoir "le nombre a n'est pas dans cet intervalle", il suffit d'appliquer l'opérateur NON à cette expression. On obtient alors l'expression ! ( a > 0 && a < 1000 ).
 
Vous remarquerez que pour cet exemple, on peut se passer de l'opérateur NON en récrivant une expression plus légère, à savoir a <= 0 || a >= 1000. C'est ainsi, on peut simplifier les expressions écrites avec des opérateurs logiques pour diminuer le nombre d'opérateurs utilisés. Cela sert pour simplifier l'écriture des calculs, ou gagner marginalement en performances lors des calculs des expressions utilisant ces opérateurs. Pour la culture générale, ces techniques de simplification servent aussi dans divers domaines de l’informatique, et même en électronique. Pour les curieux, il existe un tutoriel sur le sujet sur le Site du Zéro, accessible via ce lien : L'algèbre de Boole.
 
== Évaluation en court-circuit ===
 
Dans les opérateurs logiques && et ||, on exécute obligatoirement la première comparaison avant la seconde. C'est toujours le cas : la norme du C impose de tester d'abord la première comparaison, puis d'effectuer la seconde. Ce n'est pas le cas dans d'autres langages, mais passons.
 
Ce genre de détail permet à nos opérateurs && et || d'avoir un comportement assez intéressant, qui peut être utile dans certains cas pour éviter des calculs inutiles. Pour l'illustrer, je vais reprendre l'exemple utilisé plus haut : on veut vérifier qu'un entier est compris entre 0 et 1000 (0 et 1000 ne comptent pas, ne sont pas inclus dans l'intervalle voulu). On utilise pour cela l'expression logique a > 0 && a < 1000. Et c'est là que les choses deviennent intéressantes. Supposons que a soit inférieur ou égal à zéro. Dans ce cas, on saura dès la première comparaison que notre entier n'est pas dans l'intervalle. On n'a pas besoin d'effectuer la seconde. Eh bien rassurez-vous : le langage C nous dit si jamais la première comparaison d'un && ou d'un || suffit à donner le bon résultat, la seconde comparaison n'est pas calculée.
 
Par exemple, pour l'opérateur &&, on sait d'avance que si la première comparaison est fausse, la seconde n'est pas à calculer. En effet, l'opérateur ET ne renvoie vrai que si les deux comparaisons sont vraies. Si une seule d'entre elles renvoie faux, on pas besoin de calculer l'autre. Et vu que la première comparaison, celle de gauche, est celle effectuée ne premier, on est certain que si celle-ci renvoie faux, la seconde n'est pas calculée.
 
Pour l'opérateur ||, c'est différent : la seconde comparaison n'est pas calculée quand la première comparaison est vraie. En effet, l'opérateur || renvoie vrai dès qu'une seule des deux comparaisons testées est vraie. Donc, si la première est vraie, pas besoin de calculer la seconde.
 
Ce genre de propriétés des opérateurs && et || peut-être utilisée efficacement pour éviter de faire certains calculs. Il suffit de choisir intelligemment quelle comparaison mettre à gauche de l'opérateur, suivant la situation.
Encore mieux !
 
Bien sûr, on peut aussi mélanger ces opérateurs pour créer des conditions encore plus complexes. Voici un exemple d'une expression logique plutôt complexe (et inutile, je l'ai créé uniquement pour l'exemple) :
int nb_1 = 3, nb_2 = 64, nb_3 = 12, nb_4 = 8, nb_5 = -5, nb_6 = 42;
int boolean = ((nb_1 < nb_2 && nb_2 > 32) || (nb_3 < nb_4 + nb_2 || nb_5 == 0)) && (nb_6 > nb_4);
printf("La valeur logique est egale a : %d\n", boolean);
 
Ici, la variable boolean est égale à 1, la condition est vrai. Comme vous le voyez, j'ai inséré des retours à la ligne pour la clarté du code.
 
== Parenthèses ==
 
En regardant le code écrit plus haut, vous avez surement remarqué la présence de plusieurs parenthèses : celles-ci enlèvent toute ambigüité dans les expressions créées avec des opérateurs logiques. Et oui, en mathématique on doit utiliser des parenthèses dans nos équations; et bien c'est pareil avec des expressions utilisant des opérateurs logiques. Par exemple, le code suivant :
printf( "%d\n", (a && b) || (c && d) );
 
Est différent de :
printf( "%d\n", a && (b || c) && d );
 
Pour être sûr d'avoir le résultat souhaité, ajoutez des parenthèses.