Geospace

TwitterGitHubRSS

Le problème des 8 bits

Publié le 27/11/2017

tl;dr : POSIX demande qu’un octet soit 8 bits.

Mise à jour ! Merci à Flff qui m’a indiqué des erreurs de terminologie dans ce billet. La traduction française de byte n’est pas octet mais multiplet. Un multiplet désigne la plus petite unité adressable par un ordinateur. En revanche, le mot français octet est le même en anglais et désigne explicitement un groupement de 8 bits. Un multiplet (ou byte) de 8 bits est donc un octet. La traduction française multiplet étant peu répandue, je vais utiliser l’anglicisme byte.

Il arrive souvent de faire des opérations bit à bit en langage C. Par exemple, pour parcourir un uint8_t (représente alors la plus petite unité adressable, le byte), on peut imaginer une boucle comme ci :

uint8_t byte = 42;

for (uint32_t i = 0; i < 8; ++i)
  byte >> i & 0x1;

Rien d’incroyable : on utilise l’opérateur de décallage à droite (>>) ainsi que le “et” binaire (&) pour isoler les bits de ce que nous présumons être un octet, dans une boucle.

Postez un code similaire sur Stack Overflow : vous êtes un homme mort.

Le problème des 8 bits

La violence sur Stack Overflow

On retrouve ce genre de remarque, ammenée de manière plus ou moins directe, sur quasiment tous les sujets où le problème se pose. Je l’ai aussi vu sur Reddit et entendu à Epitech Paris.

J’ai l’impression qu’on a différents types de profils :

Bref, j’crois qu’il faut arrêter la branlette intélectuelle et être un peu réaliste… Les gens qui écrivent du code pour des architectures sur lesquelles un byte ne fait pas 8 bits sont parfaitement au courant de ce qu’ils font et pour ce qui est des autres, autant les préserver de ce débat stérile et inintéressant. Notre informatique moderne repose sur l’équation 1 byte == 8 bits et franchement c’est pas grave, on s’y fait, tranquille…

La macro CHAR_BIT

Pour les hipsters paranoïaques de la portabilité il existe une macro CHAR_BIT, définie dans limits.h, censée représenter le nombre de bits par byte sur la plateforme cible, à la compilation. J’avoue ça serait pratique et ça mettrai tout le monde d’accord, on va voir ça :

$ cat /usr/include/limits.h | grep CHAR_BIT
#  define CHAR_BIT      8

Oh ! Ben alors ! Un 8 en dur ! Incroyable ! :D

C’est en fait un prérequis POSIX :

Macro: int CHAR_BIT

This is the number of bits in a char. POSIX.1-2001 requires this to be 8.

You can compute the number of bits in any data type type like this:

sizeof (type) * CHAR_BIT

Document complet ici.

Le raisonnement peut s’arrêter là : 99% des développeurs écrivent du code pour POSIX, POSIX demande 8 bits pour CHAR_BIT et c’est la valeur qui est hardcodée dans le header. Seulement, cette valeur est en fait un fallback car elle est censée être réécrite par le compilateur. Quelques lignes plus loin on a :

$ cat /usr/include/limits.h | grep "# include_next"
# include_next <limits.h>

Par exemple, avec Clang :

$ cat /usr/include/clang/3.8/include/limits.h | grep "CHAR_BIT"
#undef  CHAR_BIT
#define CHAR_BIT  __CHAR_BIT__

__CHAR_BIT__ est une macro définie par le compilateur et sa valeur est conforme à l’implémentation. Elle vaudra toujours 8 sur les systèmes POSIX et elle vaudra c’quelle vaudra sur les systèmes qui ne sont pas POSIX.

Le problème du mot

Tant qu’on y est, autant parler du problème du mot.

Le mot (ou word) est l’unité du CPU. Il arrive qu’on ai besoin de sa taille pour faire du sale. Là, pour le coup, on a un problème beaucoup plus réel. On a encore aujourd’hui une pluralité des architectures ou plus exactement une répartition quasi bipolaire entre le 32 et le 64 bits. La macro compilateur __WORDSIZE, définie dans Clang et GCC, nous renvoie la taille d’un mot en bits sur la cible de compilation.

Sur la grande majorité des implémentations, c’est la taille d’un int32_t.

Pour conlure

Tant qu’il n’y a pas de raisons de penser le contraire, on peut tout à fait partir du principe qu’un byte fera 8 bits sur la plateforme cible et faire ses dirty pointer tricks™ et autres joyeusetés à partir de là.

Quand il y a des raisons de penser le contraire, utiliser CHAR_BIT et se retenir de lacher des “You are assuming that a byte is 8 bits. This is a catastophe. Downvoting.” sur Stack Overflow.

Pour avoir la taille en bits du mot, utiliser __WORDSIZE.