IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Java et les types signés, ça marche comment?


Sujet :

Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2009
    Messages : 31
    Par défaut Java et les types signés, ça marche comment?
    Bonsoir,

    Dans le cadre d'un projet, je dois réalisé une appli Java qui communique avec plusieurs matériels via JNI. Du coup, j'ai besoins de travailler en unsigned pour pas mal de chose. La plupart du temps, j'utilise le type "byte" (8bits signé). Mais j'ai un problème...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    byte test = -1;
    System.out.println(Integer.toBinaryString(test));
     
    //11111111111111111111111111111111
     
    test = 125;
    System.out.println(Integer.toBinaryString(test));
     
    //1111101
    Donc, si je me souvient bien de mes cours d'infos, mon byte Java est sur 8 bits. Il est signé, donc le dernier bit est utilisé pour le signe. Du coup, on se retrouve avec une valeur max de 2⁷-1 (127).

    Quelqu'un peut m'expliquer pourquoi la valeur de "-1" tient sur 32 bits??? J'avoue que je comprends pas car je m'attendrais à une valeur de "11111111" (sur 8 bits).

    Merci d'avance

  2. #2
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Integer.toBinaryString convertit un int, pas un byte, ton byte de -1 est donc promo d'abord en integer, donc étendu à 32 bits.

    Utilise Integer.toBinaryString(byte & 0xFF) pour n'avoir que les 8 bits de base.

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par gagou7 Voir le message
    Quelqu'un peut m'expliquer pourquoi la valeur de "-1" tient sur 32 bits??? J'avoue que je comprends pas car je m'attendrais à une valeur de "11111111" (sur 8 bits).
    Tout ce qui tient sur 8 bits tient aussi sur 32 bits, de même que 64 bits, 128 bits, et aussi 9 bits, 10 bits... .

    -1 est une valeur de byte parfaitement correcte, et donc tient en effet sur 8 bits. Seulement, Integer.toBinaryString() ne traite que des ints, et les ints occupent 32 bits.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2009
    Messages : 31
    Par défaut
    Merci pour l'explication, j'avais zappé la conversion en integer...

    J'ai toutefois une autre question: J'essaie d'utiliser des unsigned integer, du coup, mon raisonnement est le suivant.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //Je lis des données équivalent à un unsigned int (32 bits), dans l'exemple je l'ai codé en dur
     
    byte[] bytes = {(byte) 0xE0,(byte) 0x3A,(byte) 0xEC,0x02};
     
    // Mes bytes sont en big-endian, du coup, pour récupérer la valeur, je fais comme ça:
     
    int value = (((bytes[0] & 0xff) << 24) | ((bytes[1] & 0xff) << 16) |
    				  ((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff));
     
    //Jusque là tout ce passe bien. Mais ma variable "value" étant un integer (32 bits) signé, si je tente d'afficher la valeur, j'obtiens un nombre négatif (normal vu que mon nombre est grand et que le MSB est à 1).
     
    System.out.println(value); // -533009406 (en binaire: 11100000001110101110110000000010)
    Mon idée est de convertir mon "value" dans un type plus grand ("long" de 64bits) et d'enlever les bits mis à 1 qui font de lui un nombre négatif.

    En gros, mon "value" vaut : 11100000001110101110110000000010
    Une fois passer en "long", il devrait valoir: 11111111111111111111111111111111 11100000001110101110110000000010
    Je devrais pouvoir extraire la valeur positive grâce à "&0xFFFFFFFF".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.out.println(((long)value)&0xFFFFFFFF); //Renvoie toujours un nombre négatif...
    Pourquoi est-ce que j'ai toujours un nombre négatif? La fonction d'affichage (System.out.println()) supporte les long et ne fait pas de conversion implicite en integer pourtant... Je devrais obtenir 3761957890, non?

    Merci encore une fois pour votre aide

  5. #5
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Août 2011
    Messages
    342
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Août 2011
    Messages : 342
    Par défaut
    Citation Envoyé par gagou7 Voir le message
    Merci pour l'explication, j'avais zappé la conversion en integer...

    J'ai toutefois une autre question: J'essaie d'utiliser des unsigned integer, du coup, mon raisonnement est le suivant.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //Je lis des données équivalent à un unsigned int (32 bits), dans l'exemple je l'ai codé en dur
     
    byte[] bytes = {(byte) 0xE0,(byte) 0x3A,(byte) 0xEC,0x02};
     
    // Mes bytes sont en big-endian, du coup, pour récupérer la valeur, je fais comme ça:
     
    int value = (((bytes[0] & 0xff) << 24) | ((bytes[1] & 0xff) << 16) |
    				  ((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff));
     
    //Jusque là tout ce passe bien. Mais ma variable "value" étant un integer (32 bits) signé, si je tente d'afficher la valeur, j'obtiens un nombre négatif (normal vu que mon nombre est grand et que le MSB est à 1).
     
    System.out.println(value); // -533009406 (en binaire: 11100000001110101110110000000010)
    Mon idée est de convertir mon "value" dans un type plus grand ("long" de 64bits) et d'enlever les bits mis à 1 qui font de lui un nombre négatif.

    En gros, mon "value" vaut : 11100000001110101110110000000010
    Une fois passer en "long", il devrait valoir: 11111111111111111111111111111111 11100000001110101110110000000010
    Je devrais pouvoir extraire la valeur positive grâce à "&0xFFFFFFFF".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.out.println(((long)value)&0xFFFFFFFF); //Renvoie toujours un nombre négatif...
    Pourquoi est-ce que j'ai toujours un nombre négatif? La fonction d'affichage (System.out.println()) supporte les long et ne fait pas de conversion implicite en integer pourtant... Je devrais obtenir 3761957890, non?

    Merci encore une fois pour votre aide
    En faisant un et logique comme celui là tu ne mets jamais à 0 le bit de signe.

    Edit : faut que je compte les F D'abord ><

    Edit2 : pourquoi tu n'affectes pas directement à un long ?

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2009
    Messages : 31
    Par défaut
    Citation Envoyé par GPPro Voir le message
    En faisant un et logique comme celui là tu ne mets jamais à 0 le bit de signe.

    Edit : faut que je compte les F D'abord ><

    Edit2 : pourquoi tu n'affectes pas directement à un long ?
    Si je l'assigne directement en "long", ça ne change rien...

    En faite j'ai trouvé C'est que Java quand il voit un 0xffffffff, il le cast en integer par défaut, même si on fait "var&(long)0xffffffff", le cast aura lieu et le 0xffffffff vaudra toujours "-1". La solution c'est de lui dire que notre nombre est par défaut un "long", ce qui nous donne 0xffffffffL. Du coup, ça marche nickel maintenant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    byte[] bytes = {(byte) 0xE0,(byte) 0x3A,(byte) 0xEC,0x02};
     
    int value = (((bytes[0] & 0xff) << 24) | ((bytes[1] & 0xff) << 16) |
    				  ((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff));
     
    System.out.println(value&0xffffffffL);
    Merci encore !

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par gagou7 Voir le message
    En faite j'ai trouvé C'est que Java quand il voit un 0xffffffff, il le cast en integer par défaut, même si on fait "var&(long)0xffffffff", le cast aura lieu et le 0xffffffff vaudra toujours "-1". La solution c'est de lui dire que notre nombre est par défaut un "long", ce qui nous donne 0xffffffffL.
    La cause et la résolution sont bonnes. Mais l'explication est incorrecte : Java ne cast rien vers int.

    0xffffffff est un int, dès le départ. Un int qui vaut -1.
    Lorsque Java voit une expression qui mêle des ints et des longs, comme
    Avec value de type long, et 0xffffffff de type intrinsèque int, Java décide que l'expression est de type le plus large : long.
    Il commence donc par élargir les types ints vers le type long. Donc il élargit 0xffffffff vers le type long. Valeurs en tant que int : -1. Donc valeur en tant que long : -1. Donc après conversion en long, il n'y a toujours que des 1, et donc appliquer un & dessus n'a aucun effet.

    En utilisant 0xffffffffL, c'est un long dès le départ, et c'est lui qui fait en sorte que l'expression soit de type long. Il n'a pas besoin d'être converti, et va effectivement faire passer tous les 32 bits de poids fort à zéro.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    La question étant plutot, a part l'affichage qui vous gène (et peux donc être corrigé à l'affichage), pourquoi avoir besoin de "unsigned"?

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2009
    Messages : 31
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    La question étant plutot, a part l'affichage qui vous gène (et peux donc être corrigé à l'affichage), pourquoi avoir besoin de "unsigned"?
    Très bonne question C'est parce que mon appli Java récupère des valeurs "raw" sous forme de byte en provenance de différent périphérique (CAN, RS232 et SPI) grâce à JNI. Je dois traiter ces byte pour les reconvertir en double, float, int ou short.

    Du coup, j'ai besoins de bien comprendre comment fonctionne Java au niveau des différents types qu'il offre. Dans le cas présenté ici, c'est uniquement pour avoir le bon affichage comme si c'était un unsigned (même si en faite on place la valeur dans une variable plus grande pour que le bit de signe ne soit pas interprété).

    On pourrait croire que signed ou unsigned, peut importe car au niveau binaire ça ne change rien, mais c'est faux ! Le faite que le type unsigned n'existe pas en Java pose des problèmes lorsqu'on passe d'un type à un autre avec des variables dont le MSB est à 1. En effet, pour que la valeur soit toujours négative, des "1" sont rajoutés dans certains cas. Du coup, lorsque l'on s'amuse avec des masques et des shift et qu'on ne connait pas forcément comment Java fonctionne, on se retrouve avec des "castings implicite" en "int" qui rajoute des "1" et qui peuvent perturber nos calcules.

    Le problème est aussi présent lorsque l'on shift à droite si on utilise pas le bonne opérateur (">>>" au lieu de ">>").

    Entre temps et en faisant pas mal de test, je suis tombé sur ce site qui explique comment fonctionne Java avec les opérateurs de "shiftage".

    Dans mon cas précis, l'appli devra tourner sur un système embarqué peu puissant. Et je dois convertir des tableaux de byte (big-endian ou little-endian) en d'autres types. C'est pour ça que je n'utilise pas de ByteBuffer par exemple, car après avoir fait un petit benchmark, il s'était avérer qu'un ByteBuffer étant 100x plus lent qu'en faisant le traitement à la main (ET/OU logique, masque et shift).

    Bref, c'est des choses à savoir (que je ne savais pas) si on veut traiter/modifier des valeurs "raw" pour les rendre "utilisable" par la suite.

    En tout cas merci beaucoup de votre aide, j'ai acquis des connaissances qui me sont très utiles

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [TSQL]Comment utiliser les type BINARY ?
    Par toto4650 dans le forum Sybase
    Réponses: 4
    Dernier message: 21/12/2006, 17h38
  2. Réponses: 2
    Dernier message: 08/07/2006, 18h44
  3. comment gerer les types Objet(java)
    Par karray_ali dans le forum SQL Procédural
    Réponses: 6
    Dernier message: 09/05/2006, 23h27
  4. [C++ > C# 2.0] Comment transformer les types ?
    Par nyarla01 dans le forum C++/CLI
    Réponses: 1
    Dernier message: 16/03/2006, 12h36
  5. [VB.NET] Comment implementer les "Type" de VB6 ?
    Par cach dans le forum VB.NET
    Réponses: 2
    Dernier message: 07/02/2006, 10h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo