Le plus grand problème n'est pas l'ordre des bits dans un octet parce que comme on l'as vu dans le poste antérieur les opérateurs de shift binaires sont construits pour l'occulter. Par contre on ne peut pas ignorer l'ordre dans lequel les octets ("bytes") sont organisés en mémoire ou dans une communication. Ce problème est appelé couramment "endianness".
En général dans la mémoire d'un ordinateur on va placer un nombre en binaire dans l'ordre inverse des octets. L'ordre des bits comme on l'avait vu déjà suit généralement l'ordre des octets. Soit le nombre 3 (en base dix) sur quatre octets, pour une structure de mémoire basée sur une unité atomique de 1 octet et d'un incrément d'adresse de 1 octet.
Le nombre en Big Endian:
byte/octet addr | 0 | 1 | 2 | 3 |
---|---|---|---|---|
bit offset | 01234567 | 01234567 | 01234567 | 01234567 |
binaire | 00000000 | 00000000 | 00000000 | 00000011 |
Si on le lit en Little Endian directement, la même écriture binaire sera interprétée différemment:
byte/octet addr | 3 | 2 | 1 | 0 |
---|---|---|---|---|
bit offset | 76543210 | 76543210 | 76543210 | 76543210 |
binaire | 00000000 | 00000000 | 00000000 | 00000011 |
Le nombre lu sera en Big Endian un autre:
byte/octet addr | 0 | 1 | 2 | 3 |
---|---|---|---|---|
bit offset | 01234567 | 01234567 | 01234567 | 01234567 |
binaire | 11000000 | 00000000 | 00000000 | 0000000 |
Il faut connaître l'ordre pour lire correctement. Il faut renverser l'ordre pour ne pas lire un autre nombre.
Les processeurs Intel (x86 et Pentium) travaillent en mode Little Endian pour les octets, tandis que les processeurs Motorola (la série 680x0) travaillent en mode Big Endian pour les octets. Le MacOS était Big Endian, et il est devenu Little Endian sur Intel. Si des zones de la mémoire vive contenant des nombres sont copiées telles quelles dans un fichier, donc directement, le fichier ne pourra être lu (sans traitement particulier) que par les ordinateurs ayant une unité centrale travaillant avec le même ordre. Chaque fois qu'un ordinateur accède à fichier audio/vidéo ou un flux multimédia, l'ordinateur a besoin de savoir comment le fichier est construit. Par exemple: si vous écrivez un fichier graphique (comme un fichier .JPEG, qui est Big-Endian format) sur une machine avec un CPU Little-Endian, vous devez d'abord inverser l'ordre des octets de chaque entier vous écrivez ou un autre programme "standard" ne sera pas capable de lire le fichier. Le même problème de l'ordre d'octets se pose dans les transfers par réseau. Les protocoles d'Internet utilisent l'ordre Big Endian pour les octets, appelé donc aussi network byte ordre (ordre des octets du réseau). Il y a des fonctions qui vous aident à changer d'ordre, comme par exemple htonl() et ntohl(), sur 16 et respectivement 32 bits (HostTONework, etc.).
Les processeurs Intel (x86 et Pentium) travaillent en mode Little Endian pour les octets, tandis que les processeurs Motorola (la série 680x0) travaillent en mode Big Endian pour les octets. Le MacOS était Big Endian, et il est devenu Little Endian sur Intel. Si des zones de la mémoire vive contenant des nombres sont copiées telles quelles dans un fichier, donc directement, le fichier ne pourra être lu (sans traitement particulier) que par les ordinateurs ayant une unité centrale travaillant avec le même ordre. Chaque fois qu'un ordinateur accède à fichier audio/vidéo ou un flux multimédia, l'ordinateur a besoin de savoir comment le fichier est construit. Par exemple: si vous écrivez un fichier graphique (comme un fichier .JPEG, qui est Big-Endian format) sur une machine avec un CPU Little-Endian, vous devez d'abord inverser l'ordre des octets de chaque entier vous écrivez ou un autre programme "standard" ne sera pas capable de lire le fichier. Le même problème de l'ordre d'octets se pose dans les transfers par réseau. Les protocoles d'Internet utilisent l'ordre Big Endian pour les octets, appelé donc aussi network byte ordre (ordre des octets du réseau). Il y a des fonctions qui vous aident à changer d'ordre, comme par exemple htonl() et ntohl(), sur 16 et respectivement 32 bits (HostTONework, etc.).
Bibliographie:
- Byte and Bit Order Dissection, By Kevin Kaichuan He, Linux Jurnal
- Writing endian-independent code in C, by Harsha S. Adiga, IBM developerworks
- Endianness White Paper Intel
/*==============================================================*/
/*==============================================================*/
/*==============================================================*/
/**
*
* @Synopsis : Comment a l'air un int en little endian
**/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void bits_1byte(unsigned char x)
{
int k;
for(k = 0; k < 8; x <<= 1, k++)
/*
de MS bit (most signficant) a LS bit (least significant) pour les humains
*/
putchar('0' + ((x&128)>>7));
}
/* les bits d'un int= 4 bytes*/
void bits_4bytes(unsigned int value)
{
/*Bytes 0,1,2,3*/
unsigned int B0,B1,B2,B3;
/*l'octet le plus significatif obtenu avec des shifts*/
B0=(value>>24) & 0xFF;
B1=(value>>16) & 0xFF;
B2=(value>>8) & 0xFF;
B3=value&0xFF;
printf("\n");
printf("-------- | -------- | -------- | -------- |\n");
bits_1byte(B0);
printf(" | ");
bits_1byte(B1);
printf(" | ");
bits_1byte(B2);
printf(" | ");
bits_1byte(B3);
printf(" |\n");
}
unsigned int LittleEndianInt ( )
/* nombre de test: 256+3 */
{
struct { unsigned int
a0:1,a1:1,a2:1,a3:1,a4:1,a5:1,a6:1,a7:1,
b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1,
c0:1,c1:1,c2:1,c3:1,c4:1,c5:1,c6:1,c7:1,
d0:1,d1:1,d2:1,d3:1,d4:1,d5:1,d6:1,d7:1;
}t;
/*
&t nous donne l'adresse du premier champ de la struct a0
et l'adresse la plus basse, donc j'ecris le nombre de test
256+3 en little endian en partant de &t
*/
t.a0 = 1;t.a1 = 1;t.a2 = 0;t.a3 = 0;
t.a4 = 0;t.a5 = 0;t.a6 = 0;t.a7 = 0;
t.b0 = 1;t.b1 = 0;t.b2 = 0;t.b3 = 0;
t.b4 = 0;t.b5 = 0;t.b6 = 0;t.b7 = 0;
t.c0 = 0;t.c1 = 0;t.c2 = 0;t.c3 = 0;
t.c4 = 0;t.c5 = 0;t.c6 = 0;t.c7 = 0;
t.d0 = 0;t.d1 = 0;t.d2 = 0;t.d3 = 0;
t.d4 = 0;t.d5 = 0;t.d6 = 0;t.d7 = 0;
return *(unsigned int*)(&t);
/*
prend l'adresse la plus basse (&t) initialise avec elle
un pointeur sur un entier (unsigned int*) et recupere
sa valeur avec l'operateur de déréférencement "*"
*/
}
unsigned ReverseBitsIntLittleEndian (unsigned int Nb )
{
struct { unsigned int
a0:1,a1:1,a2:1,a3:1,a4:1,a5:1,a6:1,a7:1,
b0:1,b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1,
c0:1,c1:1,c2:1,c3:1,c4:1,c5:1,c6:1,c7:1,
d0:1,d1:1,d2:1,d3:1,d4:1,d5:1,d6:1,d7:1;
}t;
/*
en big endian &t nous donne l'adresse du champ de la struct d7 et
l'adresse la plus haute du nombre
*/
/*
les shifts manipulent les puissances de 2 "<<b"=*2^b ">>b"=1/(2^b)
*/
t.d7 = (Nb & 1);Nb=Nb>>1;t.d6 = (Nb & 1);Nb=Nb>>1;
t.d5 = (Nb & 1);Nb=Nb>>1;t.d4 = (Nb & 1);Nb=Nb>>1;
t.d3 = (Nb & 1);Nb=Nb>>1;t.d2 = (Nb & 1);Nb=Nb>>1;
t.d1 = (Nb & 1);Nb=Nb>>1;t.d0 = (Nb & 1);Nb=Nb>>1;
t.c7 = (Nb&1); Nb=Nb>>1;t.c6 = (Nb & 1);Nb=Nb>>1;
t.c5 = (Nb&1); Nb=Nb>>1;t.c4 = (Nb & 1);Nb=Nb>>1;
t.c3 = (Nb & 1);Nb=Nb>>1;t.c2 = (Nb & 1);Nb=Nb>>1;
t.c1 = (Nb & 1);Nb=Nb>>1;t.c0 = (Nb & 1);Nb=Nb>>1;
t.b7 = (Nb&1); Nb=Nb>>1;t.b6 = (Nb & 1);Nb=Nb>>1;
t.b5 = (Nb&1); Nb=Nb>>1;t.b4 = (Nb & 1);Nb=Nb>>1;
t.b3 = (Nb & 1);Nb=Nb>>1;t.b2 = (Nb & 1);Nb=Nb>>1;
t.b1 = (Nb & 1);Nb=Nb>>1;t.b0 = (Nb & 1);Nb=Nb>>1;
t.a7 = (Nb&1); Nb=Nb>>1;t.a6 = (Nb & 1);Nb=Nb>>1;
t.a5 = (Nb&1); Nb=Nb>>1;t.a4 = (Nb & 1);Nb=Nb>>1;
t.a3 = (Nb & 1);Nb=Nb>>1;t.a2 = (Nb & 1);Nb=Nb>>1;
t.a1 = (Nb & 1);Nb=Nb>>1;t.a0 = (Nb & 1);Nb=Nb>>1;
return *(unsigned int*)(&t);
}
int main(int argc, char * argv [])
{
printf("Valeur de test introduite en Little Endian a la main :256+3=259");
unsigned int NbTest = LittleEndianInt();
bits_4bytes(NbTest);
/*
transtypage du int=> char
je recupere dans le char l'octet/byte le moins significatif
*/
printf("Adresse memoire basse \n");
unsigned char c=0;
c = *(unsigned char *)(&NbTest);
bits_1byte(c);
printf("\n");
printf("\n");
printf("Le bit de plus faible poids et 1 ou bien 0?\n");
putchar('0' + (c & 1));
printf("\n");
printf("\n");
printf("Votre nombre\n");
unsigned int Nombre;
scanf ("%i",&Nombre);
c=0;
c = *(unsigned char *)(&Nombre);
printf("\n");
printf("Nombre en binaire \n");
printf("Lowest memory address ");
bits_1byte(c);
printf("\n");
bits_4bytes(Nombre);
printf("\n");
printf("\n");
printf("Bits renverses\n");
unsigned int NbRev=ReverseBitsIntLittleEndian(Nombre);
printf("Adresse memoire basse ");
c=0;
c = *(unsigned char *)(&NbRev);
printf("\n");
bits_1byte(c);
printf("\n");
bits_4bytes(NbRev);
printf("%u",NbRev);
printf("\n");
return 0;
} // main()
/*==============================================================*/
/*==============================================================*/
/*==============================================================*/
/*
pcad:dirfile andreea$ ./ex.run
Valeur de test introduite en Little Endian a la main :256+3=259
-------- | -------- | -------- | -------- |
00000000 | 00000000 | 00000001 | 00000011 |
Adresse memoire basse
00000011
Le bit de plus faible poids et 1 ou bien 0?
1
Votre nombre
2147483647
Nombre en binaire
Lowest memory address 11111111
-------- | -------- | -------- | -------- |
01111111 | 11111111 | 11111111 | 11111111 |
Bits renverses
Adresse memoire basse
11111110
-------- | -------- | -------- | -------- |
11111111 | 11111111 | 11111111 | 11111110 |
4294967294
*/
Aucun commentaire:
Enregistrer un commentaire