Dans le code suivant:
short = ((byte2 << 8) | (byte1 & 0xFF))
Quel est le but de &0xFF
? Parce que parfois je le vois écrit comme:
short = ((byte2 << 8) | byte1)
Et cela semble bien fonctionner aussi?
Anding un entier avec 0xFF
ne laisse que l'octet le moins significatif. Par exemple, pour obtenir le premier octet dans un short s
, vous pouvez écrire s & 0xFF
. Ceci est généralement appelé "masquage". Si byte1
est soit un type à un seul octet (comme uint8_t
) ou est déjà inférieur à 256 (et a donc pour résultat des zéros à l'exception de l'octet le moins significatif), il n'est pas nécessaire de masquer les bits supérieurs, car ils sont déjà nuls.
Voir tristopiaLa réponse de Patrick Schlüter ci-dessous lorsque vous travaillez avec des types signés. Lorsque vous effectuez des opérations au niveau des bits, je vous recommande de ne travailler qu'avec des types non signés.
si byte1
est un type entier de 8 bits, il ne sert à rien, s'il est supérieur à 8 bits, il vous donnera essentiellement les 8 derniers bits de la valeur:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
& 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
-------------------------------
0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1
Le danger de la deuxième expression survient si le type de byte1
est char
. Dans ce cas, certaines implémentations peuvent avoir signed char
, ce qui entraînera une extension de signature lors de l'évaluation.
signed char byte1 = 0x80;
signed char byte2 = 0x10;
unsigned short value1 = ((byte2 << 8) | (byte1 & 0xFF));
unsigned short value2 = ((byte2 << 8) | byte1);
printf("value1=%hu %hx\n", value1, value1);
printf("value2=%hu %hx\n", value2, value2);
imprimera
value1=4224 1080 right
value2=65408 ff80 wrong!!
Je l’ai essayé sur gcc v3.4.6 sur Solaris SPARC 64 bits et le résultat est identique à byte1
et byte2
déclaré comme char
.
TL; DR
Le masquage consiste à éviter l’extension de signe implicite.
EDIT: J'ai vérifié, c'est le même comportement en C++.
En supposant que votre byte1
est un octet (8bits), lorsque vous effectuez un ET au niveau des bits d'un octet avec 0xFF, vous obtenez le même octet.
Donc, byte1
est identique à byte1 & 0xFF
Disons que byte1
est 01001101
, puis byte1 & 0xFF = 01001101 & 11111111 = 01001101 = byte1
Si octet1 est d'un autre type, par exemple un entier de 4 octets, AND au niveau du bit AND avec 0xFF vous laisse avec l'octet le moins significatif (8 bits) de l'octet1.
Le byte1 & 0xff
garantit que seuls les 8 bits les moins significatifs de byte1
peuvent être non nuls.
si byte1
est déjà un type non signé qui n'a que 8 bits (par exemple, char
dans certains cas, ou unsigned char
dans la plupart des cas), cela ne fera aucune différence/est totalement inutile.
Si byte1
est un type signé ou comporte plus de 8 bits (par exemple, short
, int
, long
) et que l’un des bits sauf le 8 moins significatif soit défini, il y aura une différence les bits supérieurs avant or
ing avec l’autre variable, donc cet opérande de or
n’affecte que les 8 bits les moins significatifs du résultat).
il efface tous les bits qui ne sont pas dans le premier octet
& 0xFF
seul garantit que, si les octets sont plus longs que 8 bits (autorisés par la norme de langue), les autres sont ignorés.
Et cela semble bien fonctionner aussi?
Si le résultat est supérieur à SHRT_MAX
, vous obtenez un comportement indéfini. À cet égard, les deux fonctionneront également mal.