OVH Cloud OVH Cloud

Travailler avec des bytes en C

48 réponses
Avatar
simon.bree
Bonjour,

J'ai un buffer de byte en C.

J'ai trouver sous java que pour transformer un byte en entier on=20
utilise :
(buffer[0] & 0xff) | ((buffer[1] & 0xff) << 8) | ((buffer[2] & 0xff)=20
<< 16) | (buffer[3] << 24)

Estg-ce la m=EAme chose en C? Et si oui, pourriez-vous m'expliquer cette=20
syntaxe?

Merci d'avance,
Simon

10 réponses

1 2 3 4 5
Avatar
Xavier Roche
(buffer[0] & 0xff) | ((buffer[1] & 0xff) << 8) | ((buffer[2] & 0xff)
<< 16) | (buffer[3] << 24)


Déja, il faut savoir que cette représentation est en little endian (le
"petit bout", càd les octets de poids les plus faibles, sont en premier)
et ne sera pas toujours compatible selon les cas avec la plate-forme
voulue. Disons que, dans des représentations réseau, c'est effectivement
le plus courant.

Sinon le "& 0xff" qui masque les 8 premiers bits ne sert pas à grand
chose (buffer[n] est déja sur 8 bits), par contre un cast de chaque
octet en uint avant le décalage me parait sécurisant, dans la mesure où
le type résultant d'un (unsigned char)<<n n'est pas à priori forcément
un int..

J'aurais plutôt écrit:

unsigned int foo = ( (unsigned int) buffer[0] )
| ( ( (unsigned int) buffer[1] ) << 8 )
| ( ( (unsigned int) buffer[2] ) << 16 )
| ( ( (unsigned int) buffer[3] ) << 24 );

Avatar
simon.bree
Merci Xavier et Eric pour vos réponses rapides.

Ok, j'ai compris le << (décalage) et le | (ou logique). Mais pas trop
le & 0xff.

J'imagine que le &, c'est le "et", mais en quoi cela masque les 8 bits
de poids faible d'en entier?

Pour moi, un byte, c'est 8 bits, donc un entier entre 0 et 255. Comme
le disait Xavier, pourquoi masquer des bits alors? Et pourquoi le
(unsigned char)<<n n'est pas forcement un int?

Un byte en C, c'est bien équivalement à un char?

Simon
Avatar
Xavier Roche
J'imagine que le &, c'est le "et", mais en quoi cela masque les 8 bits
de poids faible d'en entier?


0xff c'est 255 (càd 11111111), donc les 8 premiers bits de poids faibles
à "1".

(unsigned char)<<n n'est pas forcement un int?


En fait si, a priori le standard étend en "int" avant de faire le shift.

Avatar
Pierre Maurette
Merci Xavier et Eric pour vos réponses rapides.

Ok, j'ai compris le << (décalage) et le | (ou logique). Mais pas trop
le & 0xff.

J'imagine que le &, c'est le "et", mais en quoi cela masque les 8 bits
de poids faible d'en entier?

Pour moi, un byte, c'est 8 bits, donc un entier entre 0 et 255. Comme
le disait Xavier, pourquoi masquer des bits alors? Et pourquoi le
(unsigned char)<<n n'est pas forcement un int?


Dans votre code Java on ne sait pas de quel type est buffer[]. Il
semble que ce soit un tableau de int. Si par exemple vous initialisez
un int par un byte négatif (bit de poids fort ou bit de signe allumé)
je suppose que ce bit de signe est propagé. C'est à dire que les 3
octets de poids fort sont à FFF. D'où le masquage nécessaire.

Un byte en C, c'est bien équivalement à un char?


Un unsigned char représente mieux l'idée que je me fais du byte. Et si
vous pensez octet, ce que votre code laisse supposer, il faut que
CHAR_BIT (<limits.h>) vaille 8.
Voyez si vous pouvez déclarer un uint8_t de <stdint.h>, et postez un
code en C qui illustre mieux votre problème.

--
Pierre Maurette

Avatar
Eric Levenez
Le 27/01/07 13:27, dans
,
«  » a écrit :

J'imagine que le &, c'est le "et", mais en quoi cela masque les 8 bits
de poids faible d'en entier?


Si a vaut 0x12345678 et si b vaut 0x00FF000F alors (a & b) vaut 0x0034008.

Le 0xff est un masque où les 8 bits de poids faible sont à 1. Le 0xff, c'est
la même chose que 255 ou que 0377 ou 0x000000ff.

Un "et" logique entre 255 et un entier donnera donc les 8 bits de poids
faible de ce nombre.

Pour moi, un byte, c'est 8 bits, donc un entier entre 0 et 255.


Non.

L'unité de base du C est le char, c'est le plus petit élément adressable en
mémoire. Tout est multiple de la taille d'un char. Par exemple pour allouer
de la mémoire, on utilise malloc en lui demandant un multiple de la taille
d'un char. Par définition sizeof(char) vaut 1 pour indiquer que c'est
l'élément de base. Mais ce 1 ne veut pas dire 1 octet, mais une unité de
mesure.

Par exemple sur un DSP 32 bits, un char est typiquement un 32 bits (soit 4
octets), contrairement à un char qui sur, disons un Pentium, vaut 1 octet.
Ainsi sur un Pentium, la chaîne "toto" fait 5 octets de long (ne pas oublier
le '' final), et sur un DSP 32 bits, cette chaîne fait 20 octets; mais
dans les 2 cas le taille est de 5 char soit 5 bytes.

En français la taille d'un char en C est appelée multiplet et en anglais
c'est byte. Ce byte ne vaut pas 1 octet, contrairement à bien des idées
reçues. C'est pour cela que dans les normes de télécom en anglais, l'octet
se dit octet (oui, c'est octet en anglais et non byte).

Enfin, dernière chose à savoir, c'est qu'un char en C peut être signé ou
non, cela dépend de l'implémentation. C'est pour cela qu'il existe les types
"signed char" et "unsigned char". Le "signed char" est un entier qui va au
minimum de -127 à +127 et le "unsigned char" va au minimum de 0 à 255.

Sur un Pentium (toujours pour l'exemple), un char sera typiquement signé et
ira de -128 à +127 (le -128 est un plus par rapport à la norme qui demande
juste -127). Sur un DSP 32 bits, un "unsigned char" ira de 0 à 2147483647.

Comme
le disait Xavier, pourquoi masquer des bits alors?


Le tableau qui sert au calcul peut valoir plus de 255. Dans on exemple :

buffer[0] & 0xff

Si buffer[0] contient 0x1234, alors le résultat sera 0x34.

Et pourquoi le
(unsigned char)<<n n'est pas forcement un int?


Les types sont différents.

Un byte en C, c'est bien équivalement à un char?


Oui. Mais ce n'est pas l'équivalent d'un octet.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.

Avatar
Stephane Chazelas
2007-01-27, 15:20(+01), Eric Levenez:
[...]
Sur un DSP 32 bits, un "unsigned char" ira de 0 à 2147483647.
[...]


Pourquoi n'est-ce pas de 0 à 4294967295 ?

--
Stéphane

Avatar
Pierre Maurette
[...]
Un "et" logique entre 255 et un entier donnera donc les 8 bits de poids
faible de ce nombre.


Pour moi, ça donnera 0 si "un entier" est égal à 0, 1 dans les autres
cas.

--
Pierre Maurette

Avatar
Eric Levenez
Le 27/01/07 15:30, dans ,
« Stephane Chazelas » a écrit :

2007-01-27, 15:20(+01), Eric Levenez:
[...]
Sur un DSP 32 bits, un "unsigned char" ira de 0 à 2147483647.
[...]


Pourquoi n'est-ce pas de 0 à 4294967295 ?


Heu, oui, bien sûr.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
Eric Levenez
Le 27/01/07 15:59, dans , « Pierre
Maurette » a écrit :

[...]
Un "et" logique entre 255 et un entier donnera donc les 8 bits de poids
faible de ce nombre.


Pour moi, ça donnera 0 si "un entier" est égal à 0, 1 dans les autres
cas.


J'aurais pas dû dire logique. Content ?

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
Pierre Maurette
Le 27/01/07 15:59, dans , « Pierre
Maurette » a écrit :

[...]
Un "et" logique entre 255 et un entier donnera donc les 8 bits de poids
faible de ce nombre.


Pour moi, ça donnera 0 si "un entier" est égal à 0, 1 dans les autres
cas.


J'aurais pas dû dire logique. Content ?


"Content" n'est pas le fond du problème. Il y a quand même un souci à
confondre un opérateur logique et un opérateur arithmétique (bitwise).

--
Pierre Maurette



1 2 3 4 5