Blog

Aide-mémoire sur le boutisme en C

J’ai parfois l’impression qu’en tant que bioinformaticien occasionnel, je passe davantage de temps à convertir des fichiers de données d’un format à un autre (la bioinformatique n’étant pas avare en matière de formats de données) qu’à faire des choses intéressantes avec les données contenues dans lesdits fichiers.

La plupart du temps, les formats en question sont textuels (GenBank, Fasta, etc.). Mais il m’arrive de tomber sur des formats binaires, généralement issus de logiciels propriétaires. Et là, peut alors se poser la question du boutisme (endianness ; certains auteurs parlent aussi de sexe des octets) des valeurs numériques que l’on trouve dans ces formats, dès lors que celles-ci sont codées sur plus d’un octet.

Cette note est un simple aide-mémoire sur cette question.

Rappel sur le boutisme

Un nombre stocké sur deux octets (par exemple 0xCAFE) peut être représenté en mémoire de deux façons différentes :

Cela s’applique aussi aux nombres stockés sur 4 et 8 octets, à ceci près qu’il existe plus de deux formats pour ces nombres, puisqu’on peut jouer non seulement avec l’ordre des octets mais aussi avec l’ordre des mots de deux et quatre octets.

Ainsi, le nombre 0xDECAFBAD peut être représenté des manières suivantes :

Dans le reste de cette note, je négligerai ces deux derniers cas pour ne parler que des cas « simples » — et a priori les plus fréquents — de grand-boutisme et petit-boutisme au niveau des octets.

Chaque machine ou application décide librement et arbitrairement de ses préférences boutistes. Les processeurs Intel sont notoirement petit-boutistes, tandis que les processeurs PowerPC qui armaient les anciennes générations de machines Apple étaient grand-boutistes. Plusieurs protocoles réseau utilisent le format grand-boutien, ce qui vaut à ce format d’être parfois appelé (notamment dans les fonctions de conversion, cf. ci-dessous) le network order (par opposition au host order, le format utilisé par la machine).

Détecter l’endianness avec Autoconf

Pour les projets autoconfisqués, la macro Autoconf AC_C_BIGENDIAN permet de tester l’endianness de la machine cible lors de la configuration des sources.

Utilisée le plus simplement sans paramètres, cette macro définit le symbole WORDS_BIGENDIAN si la machine cible est grand-boutiste.

dnl configure.ac
AC_C_BIGENDIAN

/* Dans le code C */
#ifdef WORDS_BIGENDIAN
    /* machine grand-boutiste */
#else
    /* machine petit-boutiste */
#endif

Conversion d’un format à un autre

Les fonctions host-to-network/network-to-host

Le standard POSIX définit une famille de quatre fonctions permettant de passer du network order (format grand-boutien) au host order (format de la machine, quel qu’il soit) et inversement :

Ces fonctions sont normalement déclarées dans arpa/inet.h. On notera qu’il n’existe pas de variantes de ces fonctions pour les entiers codés sur 64 bits.

Les fonctions de endian.h (glibc, *BSD)

La bibliothèque C GNU définit dans son en-tête endian.h une famille de fonctions (non-standard) permettant de convertir des entiers codés sur 16, 32 ou 64 bits entre le format de la machine et les formats petit- et grand-boutien :

Ces fonctions existent aussi sur les systèmes BSD, où elles sont définies dans l’en-tête sys/endian.h.

Les macros de byteswap.h (glibc)

La bibliothèque C GNU définit aussi dans son en-tête byteswap.h trois macros (non-standard) permettant d’inverser l’ordre des octets dans des entiers codés sur 16, 32 et 64 bits : bswap_16, bswap_32 et bswap_64.

Si possible, ces macros sont implémentées à l’aide d’instructions dédiées du processeur (instruction bswap sur les processeurs i486 et supérieurs).

À la différence des fonctions précédentes, ces macros renversent systématiquement l’ordre des octets sans tenir compte du format utilisé par la machine ; elles ne doivent donc être utilisées que si l’on sait que l’on doit manipuler des entiers dans un format différent de celui de l’hôte — par exemple en utilisant le symbole WORDS_BIGENDIAN produit par la macro Autoconf AC_BIG_ENDIAN, cf. ci-dessus).