Avant de continuer, il faut un minimum de compréhension du système binaire. Je vous invite donc à lire
ce tutoriel écrit par
Sheirkus.
Voilà qu'on entre dans le coeur du sujet : les opérateurs bit à bit (bitwise en anglais). Ces opérateurs sont en fait : "^", "&" et "|".
Eh oui ! Le symbole & est de nouveau utilisé, il a donc 3 fonctionnalités : donner l'adresse d'une variable, identifier les références et celle que nous allons voir.
Il existe d'autres opérateurs bit à bit, nous les verrons plus bas, par contre, ils ne sont pas nécessaire au bon fonctionnement des flags.
Si nos trois nouveaux copains sont des opérateurs au même titre que le signe d'addition (+) et de soustraction (-), il est possible de leur faire faire des calculs. Vous savez ce que donne (38 | 22) ? La réponse est 54. Quoi ? Vous ne voyez pas le lien ?
C'est normal !
En fait, ces trois symboles sont des opérateurs qui permettent de faire du calcul au niveau des bits d'une variable. Ils vont comparer chacun des bits de deux nombres binaire et renvoyer le bit en fonction de l'opérateur utilisé (Un ordinateur ne connaît que le binaire, alors pour lui (38 | 22), c'est (100110 | 10110)).
Voici ce que font chacun des opérateurs :
- & veut dire ET (comme pour && dans une condition).
- | est un OU inclusif, ce qui veut dire que ça peut être un ou l'autre ou les deux (comme pour || dans une condition).
- ^ est un OU exclusif, ce qui veut dire que ça peut être un ou l'autre mais pas les deux.
Le principe de leur fonctionnement est le même que les conditions, les opérateurs testent si la valeur vaut 1. Laissons les exemples parler d'eux-mêmes.
- 0|0 = 0
- 1|0 = 1
- 1|1 = 1
- 0&0 = 0
- 1&0 = 0
- 1&1 = 1
- 0^0 = 0
- 1^0 = 1
- 1^1 = 0
Maintenant, prenons deux valeurs hexadécimales : 0xAA et 0x55 qui, en binaire, deviennent respectivement
10101010 et
01010101. Si nous appliquons ce principe sur ces nombres binaires qui contiennent plusieurs bits, le nombre renvoyé sera comparé ainsi.
Donc, si on écrit (0xAA | 0x55), le nombre renvoyé sera 0xFF (ou 255) puisque c'est l'équivalent de 11111111 en binaire. (0xAA & 0x55) vaudra 0 (qui est la même chose que 00000000).
Pas si difficile hein ?
Pour corser les choses, prenons 2 nombres au hasard et testons les. Disons 138 et 92.
138 = 10001010
92 = 1011100
Pour calculer (138 | 92), on fait comme ceci :
Le nombre binaire qui en résulte est 11011110 qui vaut 222 en décimal. Nous pouvons donc affirmer que (138 | 92) = 222. Voyons avec les 2 autres opérateurs.
(138 & 92) = 00001000 = 8.
(138 ^ 92) = 11010110 = 214.
Sceptique ? Essayez de compiler ce petit code.
Code : C | #include <stdio.h>
int main (void)
{
printf ("%d / %d / %d", (138 | 92), (138 & 92), (138 ^ 92));
return 0;
}
|
Vous obtiendrez bel et bien :
Et maintenant, l'intérêt avec les flags ? Mais tout, voyons ! C'est ce que nous verrons plus bas, mais avant, une petite parenthèse sur deux autres opérateurs.
Les opérateurs de décalage (<< et >>).
Les opérateurs de décalage sont, eux aussi, des opérateurs bit à bit, mais leur fonctionnement est bien différent. Ils ont pour effet de
décaler de
n position chacun des chiffres d'un nombre binaire dans un certain sens.
- << décale les chiffres vers la gauche.
- >> décale les chiffres vers la droite.
Lors d'un décalage vers la gauche, des 0 sont insérés à la droite du nombre. Lors d'un décalage vers la droite, les chiffres qui sortent du nombre à droite sont perdus et des 0 sont insérés à gauche. Pour faire un décalage de 1 chiffre vers la droite du nombre 10, on doit écrire (10 >> 1) qui est l'équivalent de (1010 >> 1). Voici un dessin qui représente l'opération.
Le nombre renvoyé ici est 5 (101). Un décalage vers la gauche de 1 (10 << 1 ) aurait donné 20 (10100). On peut constater qu'un décalage vers la gauche multiplie un nombre par 2
n et un décalage vers la droite divise un nombre par 2
n.
Attention ! Si une valeur est stockée dans une variable, il faut tenir compte de la taille de celle-ci ainsi que son signe (positif ou négatif).
Eh oui ! Ça ne pouvait pas être aussi simple ! Une variable a toujours une limite en taille. Un
unsigned char, par exemple, est écrit sur 8 bits. Si on y stocke un nombre et qu'on le décale vers la gauche, les bits de poids fort (à gauche) seront
PERDUS s'ils sortent du nombre.
Si on attribue la valeur 128 (10000000) à une variable de type
unsigned char (8 bits non-signés). Un décalage de 1 chiffre vers la gauche de cette variable donnera 0 (00000000).
Ça devient encore plus compliqué si on décale une variable de type
signé. Il faut tenir compte du premier bit qui détermine le signe du nombre. Si on attribue la valeur 127 (1111111) à une variable de type
char (8 bit signés). Un décalage de 1 vers la gauche sera équivalent à -2 ou, en binaire, (1)1111110.
Mais encore ! Un décalage vers la droite n'affecte pas le bit qui détermine le signe d'un nombre, même s'il est stocké dans une variable signée. (-127 >> 1) = -64 = (1)1000000.
Il faut une bonne maîtrise du fonctionnement de la mémoire et du système binaire pour travailler les opérateurs de décalage, c'est pourquoi j'ai conseillé de lire
ce tutoriel écrit par
Sheirkus.
Et si on retournait à notre sujet ? C'est à dire les flags !