Que fait 0xff << n en Java?
À partir d'un flux d'entrée, j'ai lu les 4 premiers octets et les ai emballés pour obtenir des informations dans ce cas, la taille / len du flux.
Pour cela, j'utilise le code de suivi (exemple 1) que je copie d'un autre projet
Exemple 1: utilise un tableau d'octets, où les valeurs sont lues depuis InputStream dans le tableau nommé in_buf [] de longueur 4 et dont les valeurs sont {0,0,12,26}.
Exemple 1
int size = (((in_buf[0] & 0xff) << 24) | ((in_buf[1] & 0xff) << 16) |
((in_buf[2] & 0xff) << 8) | (in_buf[3] & 0xff)); // result its 3098
et en conséquence je deviens la valeur de la taille, sympa mais ..
J'ai besoin d'expliquer ce qui se passe ici, et j'essaie de diviser toutes les fonctions pour mieux voir ce qui se passe et déboguer, et je deviens les résultats suivants
int byte1 = ((in_buf[0] & 0xff) << 24); // result 0
int byte2 = ((in_buf[1] & 0xff) << 16); // result 0
int byte3 = ((in_buf[2] & 0xff) << 8); // result 3072
int byte4 = (in_buf[3] & 0xff); // result 26
alors je déduis que de l'exemple 1 le résultat de la taille est la somme de 0 + 0 + 3072 + 26 mais que se passe-t-il exactement (uniquement avec les valeurs 12 et 26) ici? ou quelle opération il a effectué?
Quelque chose comme ça ?
0000 0000 0000 1100 //12 << 8
0000 1100 0000 0000 // result after << 8
Et pourquoi avons-nous besoin d'utiliser le masque & 0xff ?
cuz quand vous déboguez int byte3a = (in_buf [3] & 0xff) le résultat est le même que int byte3b = in_buf [3]; donc 12 , * où valeur de in_buf [3] = 12; J'ajoute une image de mes résultats de débogage.
Que se passe-t-il ou faites-le in_buf [3] & 0xff , quelque chose comme?
0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 1111 0011 ?
Capture d'écran d'Eclipse
Réponses
quelque chose comme ça?
Oui, sauf que les opérandes subissent une promotion numérique et se transforment en un int, donc vous devriez techniquement afficher 32 bits.
et pourquoi devons-nous utiliser le masque
& 0xff?
C'est ainsi que nous traitons les octets négatifs comme positifs ints, essentiellement ce qui toUnsignedIntest en train de faire. Il ne fait rien pour les octets non négatifs, mais pour un octet négatif, disons -1:
1111 1111
Lorsque cela sera converti en intraison de la promotion numérique, il sera étendu à 32 bits. Autrement dit, le signe restera négatif. Fondamentalement, cela signifie que si le nombre est négatif, nous remplissons des 1, sinon nous remplissons des 0. Alors -1devient:
1111 1111 1111 1111 1111 1111 1111 1111
Maintenant, si vous utilisez le << 8sur cela, ce sera:
1111 1111 1111 1111 1111 1111 0000 0000
qui est -256. Voyons maintenant ce qui se passe si vous le faites & 0xffavant << 8. La promotion numérique se produit et convertit votre octet en 32 octets comme avant, mais & 0xffn'obtient que les 8 bits les moins significatifs! Ainsi, l'int devient maintenant:
0000 0000 0000 0000 0000 0000 1111 1111
C'est ainsi que vous obtenez votre octet d'origine, avec un remplissage de 0. Et puis << 8fait la chose évidente:
0000 0000 0000 0000 1111 1111 0000 0000
Le code affiché dans example1 prend les quatre premières valeurs du tableau (qui contient probablement ce que vous décrivez comme "le flux d'entrée", ou ses valeurs). Il les arrange en une seule variable, vraisemblablement un entier (non signé) d'une largeur suffisante.
Il le fait afin d'obtenir ce qui est vraisemblablement la signification sémantique des quatre premières valeurs, selon un protocole que vous n'avez pas spécifié.
Alors, pourquoi le faire de cette manière «détournée», en utilisant ces opérateurs?
L'utilisation de & 0xffgarantit que seuls les 8 bits inférieurs sont utilisés.
Ceci est redondant, c'est-à-dire inutile, au cas où vous pouvez vous fier aux valeurs du tableau provenant d'octets et ne contenant donc que des valeurs jusqu'au bit 7. Sans aucun bit supérieur (valeur 256, 512, ...) n'est pris en compte. Cela a du sens si vous ne faites pas confiance à la récupération d'octets uniques du flux dans le tableau.
Cependant en java (comme Harold l'a gentiment souligné dans un commentaire)
& 0xffn'est pas redondant en Java car byte est un type signé, et donc étendu au signe lorsqu'il est converti en int, et ces copies supplémentaires du signe doivent être supprimées. Si l'octet n'était pas signé, cela sauverait beaucoup de code comme celui-ci.
L'utilisation de << N, avec des Nmultiples de 8, déplace les huit bits "récoltés" dans la position à l'intérieur de la valeur de résultat, où ils ont l'influence correcte sur la valeur de résultat. L'un des octets (je n'utilise intentionnellement pas «premier» ici) appartient à la position la plus basse, il n'est pas décalé, sa valeur est utilisée telle quelle. Un octet est nécessaire comme octet suivant de valeur supérieure, c'est-à-dire représentant des multiples de 256 (0x100). Etc.
L'utilisation d' |assemble les pièces correctement localisées.
Maintenant, pourquoi faire cela de cette manière compliquée? L'alternative évidente est de simplement tuer tous les bits au-delà du bit 7, puis de lire le lot comme un entier de 4 octets.
La raison est le doute sur l'endianess. Vous pourriez ne pas être sûr que la disposition de quatre octets dans un certain ordre en mémoire, si elle est lue comme une valeur de 4 octets, sera interprétée comme la valeur que vous ciblez dans votre environnement. Cela est dû au fait que différents environnements peuvent être d'avis différents si l'octet à l'adresse la plus basse doit être considéré comme celui représentant les valeurs les plus basses ou les valeurs les plus élevées.
Le code affiché force un octet sélectionné aux valeurs élevées, un aux valeurs faibles et les autres entre les deux.
Cela forcera la valeur dans un octet de 8 bits.
Comme Java n'a pas de types non signés, une valeur d'octet de 0xFFest interprétée comme -1et en raison de la nature de Java, elle sera promue en un entier 32 bits, c'est-à-dire 0xFFFFFFFF.
Le masque de bits est destiné à supprimer ces bits supplémentaires pour les valeurs négatives afin qu'ils n'écrasent pas les bits lors de l'utilisation de l'opérateur OR au niveau du bit |.
Voici un exemple avec la valeur d'octet 255, bien qu'interprétée comme -1et promue enint
1111 1111 1111 1111 1111 1111 1111 (-1, but was originally an unsigned byte of 255)
& 0000 0000 0000 0000 0000 1111 1111 (0xff)
----------------------------------
0000 0000 0000 0000 0000 1111 1111 (an int with the original value of 255)
Ce sont des opérations binaires.
Que se passe-t-il exactement?
le & 0xFFmoyen fondamental, vous prenez le dernier octet.
Binaire et (&) signifie, sur le résultat, la position sera 1 seulement si 1 est dans les deux nombres à la même position (0 sinon).
Il y a un autre exemple:
0000 0001 0000 1100 (268)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0000 1100 (12)
Que se passe-t-il avec 12?
0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0000 1100 (12)
décalage:
le décalage à gauche pousse simplement les bits vers la gauche.
0000 0000 0000 1100 (12)
<< 8
-------------------
0000 1100 0000 0000 (3072)
Que se passe-t-il avec 26?
0000 0000 0001 1010 (26)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0001 1010 (26)
pourquoi avons-nous besoin d'utiliser le masque & 0xff?
Dans ce cas, vous ne le faites pas. Mais si vous travaillez avec des nombres plus grands (ou des nombres négatifs), il peut être nécessaire d'utiliser le masque. De plus, assurez-vous qu'il n'y a pas de bits supplémentaires en désordre.
Assembler tout cela avec ou:
Oui, c'est essentiellement un ajout, mais seulement dans ce cas. En fait, vous placez les octets que vous avez créés & 0xFFles uns à côté des autres pour créer un nombre. C'est la raison pour laquelle vous décalez par multiplication de 8 - chaque octet a sa propre place de taille 8.
disons que vous avez les octets X, Y, Z, W. Ensuite , (X<<24)|(Y<<16)|(Z<<8)|Wva créer un nombre construit en binaire comme suit: XYZW. Attention, il n'est pas nécessaire que ce soit la somme de ces chiffres.