Java lit-il des entiers en petit boutiste ou grand boutiste?

94

Je demande parce que j'envoie un flux d'octets d'un processus C à Java. Du côté C, l'entier de 32 bits a le LSB est le premier octet et MSB est le 4ème octet.

Ma question est donc la suivante: du côté Java, lorsque nous lisons l'octet tel qu'il a été envoyé par le processus C, qu'est-ce qu'endian du côté Java?

Une question de suivi: si l'endian du côté Java n'est pas le même que celui envoyé, comment puis-je convertir entre eux?

Hhafez
la source
1
Voici mes mnémoniques pour cela, donc je n'oublierai pas: Java n'étant pas un matériel mais plutôt virtuel, est le langage d'Internet. L' ordre des octets du réseau est big endian . Par conséquent, Java est un gros boutiste .
truthadjustr

Réponses:

66

Utilisez l'ordre des octets du réseau (big endian), qui est le même que celui que Java utilise de toute façon. Voir man htons pour les différents traducteurs en C.

Egil
la source
Je ne suis pas dans ma boîte Linux maintenant mais htons est-il une des bibliothèques standard?
hhafez
Selon h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/… sa partie de la bibliothèque standard c, oui
Egil
1
htons est disponible presque partout, mais ce n'est pas en ISO C.
MSalters
1
Si vous devez utiliser autre chose que l'ordre des octets du réseau, vous pouvez soit lancer le vôtre avec des opérateurs de bits, soit utiliser les différentes versions de java.nio.Buffer
Darron
1
Selon sa page de manuel, il est défini dans POSIX.1, il devrait donc être disponible à peu près partout. Et je semble me souvenir de l'avoir utilisé dans Win32, donc ce n'est pas seulement sur les systèmes POSIX non plus.
Joachim Sauer
47

Je suis tombé ici via Google et j'ai obtenu ma réponse que Java est un gros boutiste .

En lisant les réponses, je voudrais souligner que les octets ont en effet un ordre endian, bien que heureusement, si vous n'avez traité que de microprocesseurs «grand public», il est peu probable que vous les ayez jamais rencontrés comme Intel, Motorola et Zilog tous ont convenu de la direction de décalage de leurs puces UART et que MSB d'un octet serait 2**7et LSB serait 2**0dans leurs processeurs (j'ai utilisé la notation de puissance FORTRAN pour souligner l'âge de ce truc :)).

J'ai rencontré ce problème avec des données de liaison descendante série de bits de la navette spatiale il y a plus de 20 ans lorsque nous avons remplacé un matériel d'interface de 10 000 $ par un ordinateur Mac. Un mémoire technique de la NASA a été publié à ce sujet il y a longtemps. J'ai simplement utilisé une table de recherche de 256 éléments avec les bits inversés ( table[0x01]=0x80etc.) après que chaque octet a été décalé du flux de bits.

WB Greene
la source
Grand aperçu! J'ai cette question et aucune réponse sur le Web.
Xolve
si l'un d'entre eux est public, pourriez-vous lier le dossier technique de la NASA (et peut-être les données de liaison descendante série des bits de la navette spatiale) dont vous parlez? serait fascinant, je n'ai jamais vu une chose pareille.
n611x007
3
L'endianité au niveau du bit entre également en jeu avec les formats de compression qui utilisent une certaine forme de codage Huffman (c'est-à-dire tous). Pour plus de plaisir, JPEG est "bitwise big-endian" (c'est-à-dire que le bit le plus significatif est le "premier" bit) et LZ est "bitwise little-endian". J'ai déjà travaillé sur un format de compression propriétaire qui utilisait les deux formats sous le capot. Oh, c'était amusant ...
user435779
Ayant commencé par petits morceaux, j'ai pensé que CELA était endianess pendant longtemps.
Roy Falk
20

Il n'y a pas d'entiers non signés en Java. Tous les entiers sont signés et en big endian.

Du côté C, chaque octet a le LSB au début est à gauche et le MSB à la fin.

On dirait que vous utilisez LSB comme bit le moins significatif, n'est-ce pas? LSB représente généralement l'octet le moins significatif. L'endianness n'est pas basée sur les bits mais sur les octets.

Pour convertir un octet non signé en un entier Java:

int i = (int) b & 0xFF;

Pour convertir un petit-boutiste 32 bits non signé en octet [] en Java long (du haut de ma tête, non testé):

long l = (long)b[0] & 0xFF;
l += ((long)b[1] & 0xFF) << 8;
l += ((long)b[2] & 0xFF) << 16;
l += ((long)b[3] & 0xFF) << 24;
Jonas Elfström
la source
vient de réaliser que: $ alors comment suis-je censé envoyer ce petit boutiste non signé à mon processus java pour le lire correctement?
hhafez
ce que je veux dire par le début, c'est que lsb est au début des 4 octets (c'est un int 32 bits non signé) donc je voulais dire l'octet le moins significatif
hhafez
Aussi, je convertis de C -> Java pas de Java -> C :)
hhafez
Votre code fonctionne correctement, tant que vous supprimez le point-virgule après 0xFF dans les trois dernières lignes. Je l'éditerais moi-même, mais c'est un changement de moins de 6 caractères.
Moose Morals
1
Cela a pris presque 8 ans mais finalement quelqu'un a repéré l'erreur de syntaxe. Merci @MooseMorals :)
Jonas Elfström
12

Il n'y a aucun moyen que cela puisse influencer quoi que ce soit en Java, car il n'y a pas de moyen (direct non-API) de mapper certains octets directement dans un int en Java.

Chaque API qui fait ceci ou quelque chose de similaire définit le comportement assez précisément, vous devriez donc consulter la documentation de cette API.

Joachim Sauer
la source
3
Oh, bien sûr. Les mathématiques binaires (&, |, <<, etc.) fonctionnent très bien sur les octets et les entiers. Il est assez facile de prendre des octets arbitraires et de les coller dans un entier.
Herms
8
Mais si vous faites cela, vous ne pouvez toujours pas dire quelle endianess votre JVM utilise en interne.
Darron
4
Oui, mais même là, vous ne mappez pas directement. Vous utilisez l'arithmétique qui fait exactement ce que vous lui dites, il n'y a pas d'ambiguïté. En C, vous pouvez toujours convertir un "octet *" en "long *" et le dé-référencer. Alors tu devrais te soucier de l'endianess. En Java, il n'y a pas de moyen direct et ambigu de le faire.
Joachim Sauer
Ah, je vois. Vous parliez du casting, pas des calculs binaires. Oui, dans ce cas, vous avez raison.
Herms
10
+1 pour la "recherche de la documentation", mais NOTE: la 1ère phrase n'est plus correcte puisque de nos jours, le paquet NIO propose ByteBuffer qui peut mapper des octets à des primitives et où vous pouvez changer l'ordre des octets. Voir ByteBuffer et ByteOrder
user85421
3

Je lirais les octets un par un et les combinerais en une longue valeur. De cette façon, vous contrôlez l'endianness et le processus de communication est transparent.

Wouter Lievens
la source
Voulez-vous dire pourquoi vous me rejetez?
Wouter Lievens
car même si je pouvais lire chaque octet individuellement, la finalité de l'octet envoyé serait incorrecte, je devrais donc la convertir
hhafez
23
Endianité d'un octet? Qu'est-ce que c'est que ça? Les mots sont sensibles à l'endianité, les octets individuels non.
Wouter Lievens
3
@hhafez Ce n'est pas vrai, les octets n'ont pas d'extrémité en ce qui nous concerne si vous lisez octet par octet, vous, le programmeur, êtes responsable d'attribuer les octets au bon endroit. C'est exactement ce que fait DataInputStream, il assemble simplement les octets ensemble d'une manière big endian sous le capot.
nos
2
@WouterLievens: J'ai rencontré des périphériques d'E / S (par exemple une puce d'horloge en temps réel) qui, pour une raison quelconque, envoient des données au format inversé de bits; après avoir reçu des données d'eux, il est nécessaire d'inverser les bits de chaque octet. Je suis d’accord avec vous, cependant, que l’endian-ness des octets n’est généralement pas un problème, à moins que l’on ne doive s’occuper de certaines pièces de matériel de conception étrange.
supercat du
3

S'il correspond au protocole que vous utilisez, envisagez d'utiliser un DataInputStream, où le comportement est très bien défini .

Ilja Preuß
la source
1
Il ne peut le faire que si son protocole utilise la même endianité.
Wouter Lievens
J'ai corrigé le lien et l'ai changé pour qu'il pointe vers Java 9, la version actuelle. L'API en question a cependant été introduite dans Java 1.0.
Jens Bannmann
2

Java est 'Big-endian' comme indiqué ci-dessus. Cela signifie que le MSB d'un int est sur la gauche si vous examinez la mémoire (sur un processeur Intel au moins). Le bit de signe est également dans le MSB pour tous les types d'entiers Java.
La lecture d'un entier non signé de 4 octets à partir d'un fichier binaire stocké par un système 'Little-endian' demande un peu d'adaptation en Java. ReadInt () de DataInputStream attend le format Big-endian.
Voici un exemple qui lit une valeur non signée de quatre octets (telle qu'affichée par HexEdit sous la forme 01 00 00 00) dans un entier avec une valeur de 1:

 // Declare an array of 4 shorts to hold the four unsigned bytes
 short[] tempShort = new short[4];
 for (int b = 0; b < 4; b++) {
    tempShort[b] = (short)dIStream.readUnsignedByte();           
 }
 int curVal = convToInt(tempShort);

 // Pass an array of four shorts which convert from LSB first 
 public int convToInt(short[] sb)
 {
   int answer = sb[0];
   answer += sb[1] << 8;
   answer += sb[2] << 16;
   answer += sb[3] << 24;
   return answer;        
 }
Donald W. Smith
la source
À quoi se réfère «noté ci-dessus»? L'ordre dans lequel les réponses SO sont affichées peut varier.
LarsH
0

java force en effet big endian: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.11

user12482548
la source
3
Il s'agit de l'endianness des instructions de bytecode, pas de l'endianness des données au moment de l'exécution.
kaya3
Je vote. Cet extrait de code a byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();produit un bytetableau qui est l'inverse de ce que j'ai C/C++produit. Par conséquent, la grande finalité de Java prend effet même dans les données au moment de l'exécution.
truthadjustr