samedi 13 octobre 2012

Bits, Nibbles et Octets. Tester l'Endianness I

Petit mot sur l'ordre des  bits


Intel dans son papier appelé Endianness White Paper (pp.12) fait un rappel sur le fait que même les opérations sur les bits sont endian-sensibles. Même un champ de bits défini dans un byte/octet simple est endian-sensible. Le code qui définit des champs de bits, et nibbles (groupe de 4 bits) est sujet à des conflits d'endianness en mettant en conflit la communication sur une plateforme endian opposée.
Malgré cela la <<culture Google>>  française et anglaise nous révèle que un nombre grand de gens disent le contraire. Il y a même  des cours qui le font!!! (sic transit gloria mundi!) Donc un peu de code C peut aider éclairer le sujet.
Lorsqu'on lit un nombre en binaire écrit sur un papier, l'usage fait du chiffre le plus à gauche le plus significatif car associé à la plus grande puissance de 2 dans l'écriture du nombre. La colonne des 8 représente le bit le plus significatif (msb, most significant bit), puisqu'elle contient la plus grande valeur; et la colonne des 1 représente le bit le moins significatif (lsb, least significant bit), puisqu'elle contient la plus petite valeur. L'ordre usuel sur papier est appelé ordre "big endian" (grand boutien).

Donc le nombre 3 (base dix) sur un octet s'écrit en Big Endian est: (msb<-lsb)

byte/octet addr0
bit offset 0123 4567
binaire 0000 0011


L'autre ordre utilisé est l'ordre du petit boutien (en anglais-- little endian bit ordre), le bit le plus à droite étant celui le moins significatif.
Donc le nombre 3 (base dix) s'écrit en Little Endian( lsb->msb)

byte/octet addr
0
bit offset
 7654 3210
binaire
 1100 0000

Le programme ci après se comporte différemment sur une machine little endian et sur une machine big endian, et sait même se "rendre compte" de l'endianness. De plus, il montre comment même l'ordre des bits peut changer d'une telle machine à une autre. En occurrence, sur les machines avec des processeurs Intel, même les bits sont dans l'ordre inverse.
Par exemple, sur un PC AMD Athlon 7750, le programme en question donne ceci:

This is a little endian machine.
---- same ------
01110010
Intended number initially nibble-set, in hexa: 72
---- that is ------
01110010
Number read back from the nibble, in hexa: 4e
---- which is ------
01001110

et on remarque le fait que l'ordre des bits du dernier message est exactement celui inversé par rapport aux autres énumération de la sortie du programme. (111=7 et 10=2).

#include <stdio.h>


void bits(unsigned char a, const char *m) {
    int k;
    printf("---- %s ------\n",m);
    for(k = 0; k < 8; a <<= 1, k++) {
  putchar('0' + ((a&128)>>7)); 
  /* from MSbit to LSbit, for human readability */
    }
    printf("\n");
}

int main(int argc, char **argv) {
    int                 f = -1;
    int                 k = -1;

    const int           n = 0x12345678;
/* get the lowest memory address byte */ 
    const unsigned char b = *(unsigned char *)(&n);
/*   0x72 = 01110010                  */
    const unsigned char p = 0x72;
/*sum2^n*/
    const unsigned char q = 0 * 128 + 1*64 + 1*32
    1*16 + 0*8 + 0*4 + 1*2 + 0*1
    unsigned char       r = 0

    struct {
char a:1,b:1,c:1,d:1,e:1,f:1,g:1,h:1;
    } t;

    if(b == 0x78) {
printf("This is a little endian machine.\n");
    }
    else {
printf("This is a big endian machine.\n");
    }
    
    /* 
   p is 0x72 = 01110010, and '>>' 
   behaves identically regardless of endianness       
*/
    bits(p,"same"); 

    /* 
   however, we can show that the bit order 
   is different on Intel than on e.g. SPARC  
*/

    /* 
    let us put by hand the bits from 
    0x72 = 01110010 into 't', nibble by nibble       
*/
    t.a = 0; t.b = 1; t.c = 1; t.d = 1
t.e = 0; t.f = 0; t.g = 1; t.h = 0

    /* and "read" it back as a char that "it is"               */
    r   = *(unsigned char *)(&t);

    /* and print each of these, as a value and also bit by bit */

    printf("Intended number initially nibble-set, in hexa: %x\n",q); 
/* 0x72 always      */
    bits(q,"that is");

    printf("Number read back from the nibble, in hexa: %x\n",r); 
    bits(r,"which is"); /* not the same as 'q' on little endian*/

    return(0);

}

Aucun commentaire:

Enregistrer un commentaire