web-dev-qa-db-fra.com

Peut-on créer des octets non signés dans Java

J'essaye de convertir un octet signé en non signé. Le problème est que les données que je reçois sont non signées et que Java ne prend pas en charge les octets non signés. Ainsi, lorsqu'il lit les données, il les traite comme signées.

Je l'ai essayé pour le convertir par la solution suivante de Stack Overflow.

public static int unsignedToBytes(byte a)
{
    int b = a & 0xFF;
    return b;
}

Mais une fois encore, il est converti en octet, je reçois les mêmes données signées. J'essaie d'utiliser ces données en tant que paramètre d'une fonction de Java n'acceptant qu'un octet en tant que paramètre. Par conséquent, je ne peux utiliser aucun autre type de données. Comment puis-je résoudre ce problème?

173
dln

Je ne suis pas sûr de comprendre votre question.

Je viens d'essayer ceci et pour octet -12 (valeur signée), il a renvoyé le nombre entier 244 (équivalent à la valeur d'octet non signé, mais tapé comme un int):

  public static int unsignedToBytes(byte b) {
    return b & 0xFF;
  }

  public static void main(String[] args) {
    System.out.println(unsignedToBytes((byte) -12));
  }

Est-ce ce que vous voulez faire?

Java ne permet pas d'exprimer 244 sous la forme d'une valeur byte, comme le ferait C. Pour exprimer des entiers positifs supérieurs à Byte.MAX_VALUE (127), vous devez utiliser un autre type entier, comme short, int ou long.

101
Guillaume

Le fait que les primitives soient signées dans Java n'a aucune incidence sur la façon dont elles sont représentées dans la mémoire/le transit - un octet est simplement constitué de 8 bits. Il n'y a pas d'indicateur magique pour dire "ceci est signé" ou "ceci est non signé".

Au fur et à mesure que les primitives sont signées, le compilateur Java vous évitera d'attribuer une valeur supérieure à +127 à un octet (ou inférieure à -128). Cependant, rien ne vous empêche de dédrammer un int (ou un short) pour y parvenir:

int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)

/*
 * Will print a negative int -56 because upcasting byte to int does
 * so called "sign extension" which yields those bits:
 * 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
 *
 * But you could still choose to interpret this as +200.
 */
System.out.println(b); // "-56"

/*
 * Will print a positive int 200 because bitwise AND with 0xFF will
 * zero all the 24 most significant bits that:
 * a) were added during upcasting to int which took place silently
 *    just before evaluating the bitwise AND operator.
 *    So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
 * b) were set to 1s because of "sign extension" during the upcasting
 *
 * 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
 * &
 * 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
 * =======================================
 * 0000 0000 0000 0000 0000 0000 1100 1000 (200)
 */
System.out.println(b & 0xFF); // "200"

/*
 * You would typically do this *within* the method that expected an 
 * unsigned byte and the advantage is you apply `0xFF` only once
 * and than you use the `unsignedByte` variable in all your bitwise
 * operations.
 *
 * You could use any integer type longer than `byte` for the `unsignedByte` variable,
 * i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
 * it would get casted to `int` anyway.
 */
void printUnsignedByte(byte b) {
    int unsignedByte = b & 0xFF;
    System.out.println(unsignedByte); // "200"
}
183
Adamski

Le langage Java ne fournit rien de tel que le mot clé unsigned. Un byte selon la langue spécifie une valeur comprise entre −128 - 127. Par exemple, si un byte est converti en un int Java interprétera le premier bit comme le signe et utiliser extension du signe .

Ceci étant dit, rien ne vous empêche de visualiser une byte simplement comme 8 bits et d'interpréter ces bits comme une valeur comprise entre 0 et 255. Gardez simplement à l'esprit que vous ne pouvez rien faire pour imposer votre interprétation à la méthode de quelqu'un d'autre. Si une méthode accepte un byte, cette méthode accepte une valeur comprise entre -128 et 127, sauf indication contraire explicite.

Voici quelques conversions/manipulations utiles pour votre commodité:

Conversions vers/de int

_// From int to unsigned byte
int i = 200;                    // some value between 0 and 255
byte b = (byte) i;              // 8 bits representing that value
_
_// From unsigned byte to int
byte b = 123;                   // 8 bits representing a value between 0 and 255
int i = b & 0xFF;               // an int representing the same value
_

(Ou, si vous êtes sur Java 8+, utilisez Byte.toUnsignedInt .)

Analyse/formatage

Le meilleur moyen est d'utiliser les conversions ci-dessus:

_// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");
_
_// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));
_

Arithmétique

La représentation à 2 compléments "ne fonctionne que" pour l'addition, la soustraction et la multiplication:

_// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;

byte sum  = (byte) (b1 + b2);  // 215
byte diff = (byte) (b1 - b2);  // 185
byte prod = (byte) (b2 * b2);  // 225
_

La division nécessite une conversion manuelle des opérandes:

_byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
_
39
aioobe

Il n'y a pas d'octets primitifs non signés en Java. La chose habituelle est de le lancer en caractères plus gros:

int anUnsignedByte = (int) aSignedByte & 0xff;
34
Peter Knego

Je pense que les autres réponses ont couvert la représentation de la mémoire et que vous allez gérer cela dépend du contexte dans lequel vous prévoyez de l'utiliser. J'ajouterai que Java 8 a ajouté un support pour traiter les types non signés . Dans ce cas, vous pouvez utiliser Byte.toUnsignedInt

_int unsignedInt = Byte.toUnsignedInt(myByte);
_
20
mkobit

Une note, si vous voulez l’imprimer, vous pouvez simplement dire

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
4
Kyle Kinkade

Adamski a fourni la meilleure réponse, mais elle n'est pas tout à fait complète, alors lisez sa réponse car elle explique les détails que je ne connais pas.

Si vous avez une fonction système qui nécessite la transmission d'un octet non signé, vous pouvez transmettre un octet signé car il le traitera automatiquement comme un octet non signé.

Ainsi, si une fonction système nécessite quatre octets, par exemple, 192 168 0 1 en octets non signés, vous pouvez transmettre -64 -88 0 1, et la fonction fonctionnera toujours, car le fait de les transmettre à la fonction les annulera. .

Toutefois, il est peu probable que vous rencontriez ce problème, car les fonctions système sont masquées derrière des classes pour des raisons de compatibilité entre plates-formes, bien que certaines méthodes de lecture de Java.io renvoient des octets non codés sous la forme d'un entier.

Si vous voulez que cela fonctionne, essayez d'écrire des octets signés dans un fichier et relisez-les sous forme d'octets non signés.

1
Ewe Loon

Si vous avez une fonction qui doit recevoir un octet signé, qu'attendez-vous qu'elle fasse si vous transmettez un octet non signé?

Pourquoi ne pouvez-vous utiliser aucun autre type de données?

Peu à peu, vous pouvez utiliser un octet en tant qu'octet non signé avec des traductions simples ou inexistantes. Tout dépend de la façon dont il est utilisé. Vous auriez besoin de clarifier ce que vous voulez en faire.

0
Peter Lawrey

Vous pouvez aussi:

public static int unsignedToBytes(byte a)
{
    return (int) ( ( a << 24) >>> 24);
}    

Explication:

disons a = (byte) 133;

En mémoire, il est stocké sous la forme: "1000 0101" (0x85 au format hexadécimal)

Ainsi, sa représentation traduit non signé= 133, signé= - 123 (en complément de 2)

a << 24

Lorsque le décalage à gauche est effectué 24 bits à gauche, le résultat est maintenant un entier de 4 octets, représenté par:

"10000101 00000000 00000000 00000000" (ou "0x85000000" en hexadécimal)

ensuite nous avons

(a << 24) >>> 24

et il se décale à nouveau sur les 24 bits de droite mais se remplit de zéros non significatifs. Donc, il en résulte:

"00000000 00000000 00000000 10000101" (ou "0x00000085" en hexadécimal)

et c'est la représentation non signée qui équivaut à 133.

Si vous avez essayé de transtyper a = (int) a;, alors ce qui se produirait serait de conserver la représentation de byte du complément à 2 et de le stocker aussi bien comme complément à 2:

(int) "10000101" ---> "11111111 11111111 11111111 10000101"

Et cela se traduit par: -123

0
mark_infinite

Il n'y a pas d'octet non signé en Java, mais si vous voulez afficher un octet, vous pouvez le faire,

int myInt = 144;

byte myByte = (byte) myInt;

char myChar = (char) (myByte & 0xFF);

System.out.println("myChar :" + Integer.toHexString(myChar));

Sortie:

myChar : 90

Pour plus d'informations, veuillez vérifier Comment afficher une valeur hexadécimale/octet en Java.

0
Jyo the Whiff

Bien que cela puisse paraître ennuyeux (venant de C) que Java n'inclue pas l'octet non signé dans le langage, ce n'est pas grave, car une simple opération "b & 0xFF" donne la valeur non signée pour l'octet (signé) b dans les (rares) situations où il est réellement nécessaire. Les bits ne changent pas en réalité - juste l'interprétation (ce qui est important uniquement lorsque vous effectuez par exemple des opérations mathématiques sur les valeurs).

0
Bob

Si vous pensez que vous cherchez quelque chose comme ça.

public static char toUnsigned(byte b) {
    return (char) (b >= 0 ? b : 256 + b);
}
0
Tobias Johansson