Données Hexa

Identification

Infoforall

6 - Intérêt de l'hexadécimal


Après ce long panorama sur les nombres, entiers ou non, il est temps de passer à d'autres choses à encoder.

Commençons par l'autre entité importante dans la culture humaine : le texte.

Perceval et ASCII
Perceval ne comprend rien à l'ASCII

Documents de cours : open document ou pdf

1 - ASCII

L'ordinateur ne stocke que des bits.

D'ailleurs, c'est même pire : il stocke des blocs de bits qu'on nomme octet pour le plus petit de ces blocs.

Alors, comment fait-il pour stocker des textes ?

Ben oui, il stocke des octets&nbs;!

Depuis les débuts de l'informatique, il y a eu des tables de correspondances entres les caractères courants de la langue anglo-saxonne et les valeurs qui peut prendre un octet.

On aurait pu créer un code du type :

 1  pour A,  2  pour B,  3  pour C ...

C'est oublier qu'avant d'ouvrir un texte l'ordinateur a besoin d'informations 

  • Où commence le fichier ? On utilise le caractère STX, Start of TeXt
  • Où s'arrête le fichier ? On utilise le caractère ETX, End of TeXt
  • Où doit-il passer à la ligne ? On utilise le caractère Carriage Return (Retour chariot) CR
  • ...

En plus des caractères dits imprimables, ASCII donne donc également un code normalisé aux caractères dits de contrôle.

Principe de la table ASCII

La table ASCII est devenue le standard incontournable des 128 premiers caractères. Elle est publiée pour la première fois en 1963 et est le résultat d'un groupe de travail. La table ASCII attribue des valeurs codifiées aux lettres minuscules (a-z), majuscules (A-F), aux chiffres décimaux (0-9), aux caractères de ponctuation, à quelques symboles mathématiques ou non...

Jusqu'alors, chaque matériel avait sa propre table d'encodage/décodage... Changer de support impliquait donc de changer les codes à inscrire !

La taille choisie pour l'encodage des caractères était de 7 bits. On pouvait donc encoder 27, soit 128 caractères au total. Pas un de plus. Cela représentait une place mémoire non négligeable à l'époque : on était à quelques centaines de kilo-octets (ko) à l'époque. De quoi encoder un petit livre uniquement, ou une image de qualité très médiocre.

Un petit bout de la table ASCII

Caractère encodé En binaire (7 bits) En décimal
A  100 0001  65
B  100 0010  66
C  100 0011  67

Sous cette forme de tableau avec une ligne par caractère, cela va donner 128 lignes. Cette représentation prendrait beaucoup de place.

On préfère représenter la correspondance Code/Caractère via un tableau à deux entrées.

Table ASCII en format décimal

Voilà la totalité de la table ASCII en format décimal pour les doubles entrées. Les caractères de contrôle sont en fond jaune.

_0_1_2_3_4_5_6_7_8_9
0_NULSOHSTXETXEOTENQACKBELBSHT
1_LFVTFFCRSOSIDLEDC1DC2DC3
2_DC4NAKSYNETBCANEMSUBESCFSGS
3_RSUS !"#$%&'
4_()*+,-./01
5_23456789:;
6_<=>?@ABCDE
7_FGHIJKLMNO
8_PQRSTUVWXY
9_Z[\]^_`abc
10_defghijklm
11_nopqrstuvw
12_xyz{|}~DEL
_0_1_2_3_4_5_6_7_8_9

Nous verrons la signification des différents caractères de contôle plus tard.

Sachez juste par exemple que EOT code la fin d'une transmission (End of Transmission) ou LF code le saut de ligne (sans changement de colonne) (Line Feed) ou CR (carriage return) le saut de ligne avec retour au début ...

Beaucoup de ces caractères sont utilisés sur les protocoles de communications que nous verrons plus tard.

On retrouve bien

  • le A avec un code 65 : 6 en ligne et 5 en colonne.
  • le a avec un code 97 : 9 en ligne et 7 en colonne.

Commençons par comprendre le message qu'a reçu notre grand chevalier :

01° Utiliser la table ASCII en décimal pour tenter de décoder le message reçu.

Perceval et ASCII

...CORRECTION...

Il suffit d'associer chaque valeur à la lettre que la valeur encode (s'il s'agit bien d'un texte ET que le texte a été encodé en respectant l'ASCII)

80 encode P

101 encode e

114 encode r

99 encode c

101 encode e

118 encode v

97 encode a

108 encode l

32 encode

63 encode ?

On constate quand même un problème non ?

Il reste deux cases vides dans le tableau... C'est bête. C'est simplement car le décimal n'est pas une base pratique pour représenter un octet : 256 possibilités.

Avec dix lignes sur dix colonnes, on aura juste 100 possibilités.

Or, il se trouve que 16 x 16 = 256.

Si on veut représenter sans perte de cases un tableau de ce type, le mieux est donc d'utiliser la base 16, l'hexadécimal.

Table ASCII en version hexadécimale
_0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _A _B _C _D _E _F
0_ NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI _0
1_ DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 1_
2_ !"#$%&'()*+,-./ 2_
3_ 0123456789:;<=>? 3_
4_ @ABCDEFGHIJKLMNO 4_
5_ PQRSTUVWXYZ[\]^_ 5_
6_ `abcdefghijklmno 6_
7_ pqrstuvwxyz{|}~DEL 7_
_0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F

C'est plus joli mais maintenant A vaut 41...

En réalité, non. Nous avons toujours la même valeur. Pourquoi ?

Tout simplement car 65 10 = 1000001 2 = 41 16.

Dit comme ça, ça semble compliqué mais, en réalité, cela va nous simplifier le travail et nous éviter bien des erreurs lors des conversions de base.

2 - Hexadécimal

Avant d'en montrer toute l'utilité, voyons comme fonctionne l'hexadécimal.

2.1 Cases

Voyons comment fonctionne le décodage d'un nombre en base 16 ainsi que l'addition.

Que peut-on mettre dans les cases en hexadécimal ?

Des chiffres.

Combien et lesquels ?

Base 16 donc 16 CHIFFRES :  0  -  1  -  2  -  3  -  4  -  5  -  6  -  7  -  8  -  9  -  A  -  B  -  C  -  D  -  E  -  F .

Pourquoi avoir pris des lettres plutôt que d'inventer de nouveaux symboles ? Parce que c'est plus facile ! En plus, les tables ne comportant que 128 symboles initialement, c'était plus rentable de recycler plutôt que d'en inventer de nouveaux. Il n'y avait déjà plus de place.

De 0 à 9, ce ne change pas :

N = 0 10 = 0 16

N = 1 10 = 1 16

N = 2 10 = 2 16

...

N = 9 10 = 9 16

Mais ensuite

N = 10 10 = A 16

N = 11 10 = B 16

N = 12 10 = C 16

N = 13 10 = D 16

N = 14 10 = E 16

N = 15 10 = F 16

La case de poids faible ( 1 ) est toujours située à droite.

Poids de case exprimé en puissance de 16

On peut écrire facilement le poids des cases en utilisant les puissances de 16 :

La case code 4096 256 16  1 
qu'on peut écrire sous la forme 163 162 161 160

Exemple

Si j'écris M= 3429 16, je fais ceci en réalité dans ma tête :

Nombre M = 3 4 2 9
La case code 4096 256 16 1
On obtient donc 4096*3 256*4 16*2 1*9

D'ou la valeur de M en base 10 : M = 4096*3 + 256*4 + 16*2 + 9 =  13353 .

On peut donc écrire N = 3429 16 = 13353 10.

L'exemple ne comporte aucun chiffre A à F volontairement. Difficile de savoir que 3429 est un nombre exprimé en hexadécimale si on ne l'indique pas par l'indice 16.

02° Montrer qu'on a bien N = 41 16 = 65 10. Il s'agit des deux valeurs rencontrées pour A en ASCII.

...CORRECTION...

Il suffit de calculer la valeur en base 10 avec 4 dans la case de droite et 1 dans la case de gauche..

On obtient N = 4 * 16 + 1 = 65.

03° Montrer que N = FF 16 = 255 10. Il s'agit de la valeur maximale pour un octet.

...CORRECTION...

Il suffit de calculer la valeur en base 10 avec F dans la case de droite et F dans la case de gauche.

Le chiffre F en base 16 correspond au nombre 15 en base 10.

On obtient N = 15 * 16 + 15 * 1 = 255.

04° Montrer que N = FE 16 = 254 10. Il s'agit de la valeur maximale pour un octet.

...CORRECTION...

Il suffit de calculer la valeur en base 10 avec F dans la case de droite et E dans la case de gauche.

Le chiffre E en base 16 correspond au nombre 14 en base 10.

On obtient N = 15 * 16 + 14 * 1 = 254.

2.2 Addition

Alors ça fonctionne comment l'addition ? Pourquoi F+1 donne 10 ? On se le demande non ?

Jusqu'à F, il n'y a pas de difficulté, il suffit de suivre la liste des CHIFFRES disponibles.

Base 16 donc 16 CHIFFRES :  0  -  1  -  2  -  3  -  4  -  5  -  6  -  7  -  8  -  9  -  A  -  B  -  C  -  D  -  E  -  F .

Méthode à utiliser pour incrémenter (rajouter 1)
  • Tenter de rajouter 1 dans la case de l'unité (la case de poids faible, celle de droite). Pour cela, il suffit de placer le prochain chiffre dans la liste
     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
  • Si on est déja au dernier chiffre (  F  ), on revient au premier chiffre (  0  ) dans cette case ET on rajoute un dans la case juste à gauche. On fait une retenue.

Exemple 1 :

Si on rajoute 1 à 9
on obtient A

...EXPLICATION...

On peut augmenter le chiffre de l'unité  9  en le faisant juste passer au chiffre suivant :  A .

Exemple 2 :

Si on rajoute 1 à E
on obtient F

...EXPLICATION...

On peut augmenter le chiffre de l'unité  E  en le faisant juste passer au chiffre suivant :  F .

Exemple 3 : cette fois, on va devoir rajouter une case à droite (elle contient 0 initialement puisqu'elle n'apparaît pas)

Si on rajoute 1 à F
on obtient 1 0

...EXPLICATION...

On ne peut augmenter le chiffre de l'unité qui est déjà à  F .

On la passe donc à  0  ET on incrémente la case juste à gauche.

La case de gauche était initialement à  0  : elle passe donc à  1 .

Exemple 4 :

Si on rajoute 1 à 1 3
on obtient 1 4

...EXPLICATION...

On peut augmenter le chiffre de l'unité  3  en le faisant juste passer au chiffre suivant :  4 .

Exemple 5 :

Si on rajoute 1 à F 3
on obtient F 4

...EXPLICATION...

On peut augmenter le chiffre de l'unité  3  en le faisant juste passer au chiffre suivant :  4 .

Exemple 6 :

Si on rajoute 1 à 3 F F
on obtient 4 0 0

...EXPLICATION...

On ne peut augmenter le chiffre qui est déjà à  F .

On la passe donc à  0  ET on incrémente la case juste à gauche.


La case juste à gauche était initialement à  F  : elle passe donc à  0  également et on va devoir augmenter de 1 la case suivante, la case la plus à gauche.


Le chiffre des centaines  3  passe donc à  4 .

2.3 Nombres de cas dénombrables

Si on ne possède qu'une case  ?  à remplir, on peut donc définir 16 valeurs de  0  à  15  10 ( soit  F  16).

Comme le premier cas est numéroté 0, on a bien 15+1 = 16 valeurs possibles.

Si on dispose de 2 cases  ??  à remplir, on peut définir des valeurs de  00  à  FF .

Comme le premier cas est numéroté 0, on a bien 255+1 = 256 valeurs possibles.

On voit bien qu'il y a une généralisation à trouver. Laquelle ?

Nombre de cas dénombrables en base 16

En hexadécimal, si on dispose de X cases pouvant accueillir un des 16 chiffres de la base 16, le nombre de valeurs possibles est 16X 10.

Attention : dans la mesure où le premier cas est 0, la valeur maximale est donc 16X - 1 10

Exemple : si on dispose de 4 cases

  • Le nombre de possibilité est 164 = 65 536
  • On peut alors stocker des valeurs partant de 0 jusqu'à 65535.

2.4 Bilan sur la base 16 (hexadécimal)

Résumé hexadécimal
  1. Que peut-on mettre dans les cases d'un nombre en base 16 ?
  2. Des chiffres. Combien et lesquels ?

    Base 10 donc 10 CHIFFRES :  0  -  1  -  2  -  3  -  4  -  5  -  6  -  7  -  8  -  9  -  A  -  B  -  C  -  D  -  E  -  F .

  3. On peut facilement trouver le poids des cases en utilisant les puissances de 16 :
  4. La case code 4096 256 16  1 
    qu'on peut écrire sous la forme 163 162 161 160
  5. Méthode à utiliser pour incrémenter (rajouter 1)
    • Tenter de rajouter 1 dans la case de l'unité (la case de poids faible, celle de droite). Pour cela, il suffit de placer le prochain chiffre dans la liste
       0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
    • Si on est déja au dernier chiffre (  F  ), on revient au premier chiffre (  0  ) dans cette case ET on rajoute un dans la case juste à gauche.
  6. Nombre de valeurs disponibles en base 16
  7. En hexadécimal, si on dispose de X cases pouvant accueillir un des 10 chiffres de la base 16, le nombre de valeurs possibles est 16X.

    Attention : dans la mesure où le premier cas est 0, la valeur maximale est donc 16X - 1

Bon. Ok.

Ce n'est pas si dur que ça en a l'air finalement.

M'enfin, si c'est juste pour ne pas avoir de trou dans nos tableaux de caractères, ce n'était peut-être pas la peine d'en arriver là non plus...

Vous vous doutez bien que ce n'est pas (uniquement) pour des questions de présentation qu'on utilise l'hexadécimal.

En réalité, ce système est très utilisé car il permet de convertir du binaire sans quasiment pouvoir se tromper à partir du moment où on a compris que A c'était 10, B 11, C 12, D 13, E 14 et F 15.

3 - Passage du binaire à l'hexadécimal

En réalité, ce n'est pas la séquence 80 - 101 - 114 - 99 - 101 - 118 - 97 - 108 - 32 - 63 que reçoit Perceval. Non non.

Il reçoit ceci : 01010000011001010111001001100011011001010111011001100001011011000010000000111111.

Et tout de suite, c'est moins rigolo à traduire.

On peut s'en sortir en refaisant des tas d'octets.

05° Utiliser un éditeur de texte quelconque pour copier la séquence de bits et faire des tas de 8 bits (des octets).

...CORRECTION...

Les octets : 01010000 01100101 01110010 01100011 01100101 01110110 01100001 01101100 00100000 00111111.

06° Convertir les trois premiers octets en base 10 pour vérifier si le message est bien le même que sur l'image.

Perceval et ASCII

On s'en sort mais :

  • C'est long
  • Car en fait, le cerveau humain ne parvient pas à dénombrer instinctivement et rapidement plus de 5 objets à la fois (les bits ici)

Or, un octet c'est 8 bits. La solution : faire des tas de 4 .

Lecture d'un quartet binaire en hexadécimale

 0000  donne 0 16

 0001  donne 1 16

 0010  donne 2 16

 0011  donne 3 16

 0100  donne 4 16

 0101  donne 5 16

 0110  donne 6 16

 0111  donne 7 16

 1000  donne 8 16

 1001  donne 9 16

 1010  donne A 16 ou 10 10

 1011  donne B 16 ou 11 10

 1100  donne C 16 ou 12 10

 1101  donne D 16 ou 13 10

 1110  donne E 16 ou 14 10

 1111  donne F 16 ou 15 10

Les octets étaient :  0101 0000   0110 0101   0111 0010   0110 0011   0110 0101   0111 0110   0110 0001   0110 1100   0010 0000   0011 1111  .

On peut assez facilement les transformer en base 16 :

 5 0   6 5   7 2   6 3   6 5   7 6   6 4   6 C   2 0   3 F 

07° Vérifier que les 4 premiers octets soient bien 50 65 72 63 en hexadécimal.

...CORRECTION...

Pour le premier octet, on a les quartets suivants

 0101 , ce qui donne 0+4+0+1 = 5.

 0000 , ce qui donne 0+0+0+0 = 0.

08° Vérifier le début du message en utilisant la table hexa ci-dessous.

 5 0   6 5   7 2   6 3   6 5   7 6   6 4   6 C   2 0   3 F 

Table ASCII en version hexadécimale
_0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _A _B _C _D _E _F
0_ NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI _0
1_ DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 1_
2_ !"#$%&'()*+,-./ 2_
3_ 0123456789:;<=>? 3_
4_ @ABCDEFGHIJKLMNO 4_
5_ PQRSTUVWXYZ[\]^_ 5_
6_ `abcdefghijklmno 6_
7_ pqrstuvwxyz{|}~DEL 7_
_0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F

09° Vérifier que 50 16 correspond bien à 80 10.

...CORRECTION...

Il suffit de gérer les cases avec les poids de 16 et 1.

N = 5 * 16 + 1 * 0 = 80

Il s'agit encore du P si on regarde la table en décimal. Ouf.

La première utilisation massive de l'hexadécimal en informatique date de 1956 avec l'ordinateur Bendix-G15. 450kg, plus d'un m3, pour un prix qui correspondrait actuellement à environ 500 000 $ !

BendixG15.jpg
BendixG15, image historique

Le concepteur en chef du G15 est l’informaticien et mathématicien Harry Huskey. Celui-ci avait travaillé auparavant avec le celèbre Alan Turing ainsi que sur le premier ordinateur entièrement électronique, le non moins célèbre ENIAC. Celui-ci, financé pendant la Seconde Guerre Mondiale, en 1943 prend encore plus de place :

Eniac.jpg
ENIAC, image historique

4 - Couleur et hexadécimal

Nous avons déjà vu que les écrans sont composés de pixels et que chaque pixel est décomposé en trois sous-pixels : un  Rouge , un  Vert  et un  Bleu .

Pour chacun d'eux, l'intensité du pixel est codé sur un octet.

En binaire, cela va donc de  0000 0000  à  1111 1111 .

En décimal, on obtient de  000  à  255 .

En hexadécimal, on obtient de  00  à  FF .

R :

V :

B :

+
+
=

+
+
=

Attention, les valeurs non valides sont transformées en FF.

10° Tenter de créer du rouge vif, du rouge foncé, du vert, du jaune, du gris et du blanc.

5 - Convertisseur Python

Python gère très bien les valeurs hexadécimales.

Préfixes permettant de préciser la base des nombres

Pour fournir un nombre en binaire, il fallait le précéder de 0b.

Pour l'hexadécimal, c'est 0x.

On utilise cette notation (par exemple 0xFF) car c'est plus facile que d'indiquer (et encore plus qu'afficher) les indices (par exemple FF16).

11° Utiliser les instructions suivantes dans le Shell : Python sait calculer et convertir les nombres fournis en base 16 mais affiche par défaut le résultat en base 10.

>>> 0xFF 255 >>> 0xFF + 1 256 >>> 1 + 0xF 16 >>> 0b11111111 + 0xFF 510 >>> 255 + 255 510

Nous avons également vu les fonctions natives suivantes :

  • int : elle permet de tenter de convertir l'argument (un nombre ou un string) en entier). La réponse sera visualisée par défaut sous forme décimale.
  • >>> int('0xFF', 16) 255 >>> int('255') 255 >>> int('0b11111111', 2) 16
  • bin : elle renvoie un string donnant la valeur binaire du nombre entier fourni en argument.
  • >>> bin(255) '0b11111111' >>> bin(15) '0b1111' >>> bin(0xF) '0b1111'
Fonction native hex

Cette fonction native renvoie une chaîne de caractères commençant par 0x et contenant la forme hexadécimale du nombre fourni en argument.

>>> hex(255) '0xff' >>> hex(15) '0xf' >>> hex(0b1111) '0xf' >>> hex(0b1111+1) '0x10' >>> hex(15+1) '0x10'

Comme avec la fonction bin, on peut supprimer les deux premiers caractères de la chaîne de caractères en utilisant [2:]. Cela veut dire : ne fournir que les caractères d'index 2 et plus. Il va donc supprimer de la réponse les caractères d'index 0 et 1.

>>> hex(255)[2:] 'ff' >>> hex(15)[2:] 'f' >>> hex(0b1111)[2:] 'f' >>> hex(0b1111+1)[2:] '10' >>> hex(15+1)[2:] '10'

Pour finir cette activité, voici une procédure qui permet d'afficher les codes ASCII d'une chaîne de caractères (qui ne doit donc comporter que des caractères issus de la table ASCII).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def voir_encodage(texte, encodage_voulu, base_voulue): '''Procédure qui affiche les octets encodant le texte ::param texte (str) :: le texte à analyser ::param encodage_voulu (str) :: un nom valide d'encodage ::param base_voulue (int) :: la base voulue en réponse parmi 2-10 ou 16 ..warning :: Les caractères de texte doivent être encodables avec l'encodage ..note :: toutes bases non voulues sera traitées comme 10. ''' encodage = texte.encode(encodage_voulu) for octet in encodage : if base_voulue == 2 : valeur = bin(octet)[2:].rjust(8,'0') elif base_voulue == 16 : valeur = hex(octet)[2:] else : valeur = str(octet).rjust(3,'0') print(valeur, end= " - ") voir_encodage("Perceval ?","ascii", 16)

12° Utiliser le programme pour visualiser les différentes valeurs des mêmes octets dans les 3 bases.

13° Tenter de faire de même avec un texte comportant des caractères non ASCII, comme par exemple "Perceval, ça va ?".

C'est problématique : comme le caractère ç n'existe pas dans cette table, pas moyen d'obtenir une réponse.

14° Remplacer l'encodage "ascii" par "iso8859_15" par exemple. Demander à voir le résultat en base 10. Il s'agit de la table des caractères des pays d'Europe de l'Ouest, sous le format 1 caractère encodé par un octet uniquement.

Le résultat attendu : 080 - 101 - 114 - 099 - 101 - 118 - 097 - 108 - 044 - 032 - 231 - 097 - 032 - 118 - 097 - 032 - 063 -

Le caractère en gras est le ç, encodé par un nombre supérieur à 127 car on utilise cette fois bien les 8 bits de l'octet.

Il n'y a donc que 256 possibilités de caractères différents avec les encodages sur un octet.

15° Remplacer l'encodage "iso8859_15" par "utf-8" . Demander à voir le résultat en base 10. Par comparaison, trouver les octets qui permettent d'encoder le ç.

En UTF-8 : 080 - 101 - 114 - 099 - 101 - 118 - 097 - 108 - 044 - 032 - 195 - 167 - 097 - 032 - 118 - 097 - 032 - 063 -

iso8859_15 : 080 - 101 - 114 - 099 - 101 - 118 - 097 - 108 - 044 - 032 - 231 - 097 - 032 - 118 - 097 - 032 - 063 -

En UTF-8, les caractères non-ascii sont donc encodés sur plus d'un octet : cela permet de représenter tous les caractères utilisables.

Pour le ç, cela donne donc un octet 195 et un octet 167.

Nous reviendrons en détail sur ces histoires d'encodage pendant l'activité spécifique sur les textes et leurs techniques d'encodages historiques.

Retenons donc qu'un octet n'est qu'une suite de bits et qu'on peut visualiser son contenu de plusieurs façons :

  • En binaire (base 2) : ce choix permet de clairement visualiser ce qui est stocké s'il faut décoder des informations liées à certaines valeurs de bits (bit de signe ...)
  • En décimal (base 10) : le choix le plus facile pour un humain
  • En hexadécimal (base 16) : le choix intermédiaire :
    • elle est plus facile à visualiser pour un humain que la base 2 (on a deux caractères (  2A  ) plutôt que 8 (  00101010  ) ) et
    • elle permet plus facilement de retrouver la valeur binaire que la base 10 puisqu'on ne travaille que sur des quartets.
      •  2  donne  0010 
      •  A  donne  1010 

Activité publiée le 27 10 2019
Dernière modification : 27 10 2019
Auteur : ows. h.