Java是否以小端或大端读取整数?


94

我问是因为我正在从C进程向Java发送字节流。在C端,32位整数的LSB是第一个字节,MSB是第4个字节。

所以我的问题是:在Java端,当我们读取从C进程发送的字节时,Java端的字节是什么?

后续问题:如果Java端的字节序与发送的字节序不同,如何在它们之间转换?


1
这是我的助记符,所以我不会忘记:Java不是硬件而是虚拟的,是Internet的语言。该网络字节顺序大端。因此,Java是大端
6

Answers:


66

使用网络字节顺序(大字节序),这与Java始终使用的顺序相同。有关C中不同翻译器的信息,请参见man htons。


我现在不在Linux机器上,但是htons是标准库之一吗?
hhafez

根据h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/…它是标准c库的一部分,是的
Egil

1
htons几乎在所有地方都可以使用,但ISO C中却没有
。– MSalters

1
如果您必须使用网络字节顺序以外的其他方式,则可以使用按位运算符滚动自己的名称,或者使用不同版本的java.nio.Buffer
Darron

1
根据它的手册页,它是在POSIX.1中定义的,因此应该几乎在任何地方都可以使用。而且我似乎还记得在Win32中使用它,因此它也不仅仅在POSIX系统上。
约阿希姆·绍尔

47

我通过Google偶然发现了这里,并得到了Java是大型字节序的答案。

仔细阅读答复,我想指出字节确实有一个字节顺序,尽管有幸,如果您只处理“主流”微处理器,那么您不可能像Intel,Motorola和Zilog那样遇到过字节在他们的UART芯片的移位方向上达成了共识,MSB是一个字节,2**7而LSB将2**0在他们的CPU中(我使用FORTRAN功率符号来强调这个东西的年代:))。

20年前,当我们用Mac电脑替换了价值1万美元的接口硬件时,我遇到了一些航天飞机位串行下行链路数据的问题。很久以前有一篇关于它的美国宇航局技术简介。table[0x01]=0x80在将每个字节从位流移入后,我只使用了256个元素的查找表,将位反转了(等等)。


伟大的见识!我有这个问题,网络上没有答案。
Xolve

如果其中任何一个是公开的,您能否链接您正在谈论的NASA技术简介(以及pethaps航天飞机位串行下行链路数据)?会令人着迷,我从未见过这样的事情。
13年

3
按位字节序也可以用于使用某种形式的霍夫曼编码(即所有形式)的压缩格式。为了获得更多乐趣,JPEG是“按位大尾数”(即最高有效位是“第一”位),而LZ是“按位小尾数”。我曾经研究过一种专有的压缩格式,该格式在后台使用了这两种格式。哦,那很有趣...
user435779 2014年

从零开始,我以为那是很长一段时间的耐力。
罗伊·福克

20

Java中没有无符号整数。所有整数都是带符号的,并且采用大端字节序。

在C端,每个字节的开头是LSB,左边是MSB,结尾是MSB。

听起来您是将LSB用作最低有效位,对吗?LSB通常代表最低有效字节。 字节序不是基于位而是基于字节。

要将无符号字节转换为Java整数:

int i = (int) b & 0xFF;

要将byte []中的无符号32位little-endian转换为Java long(从我的头顶开始,未经测试):

long l = (long)b[0] & 0xFF;
l += ((long)b[1] & 0xFF) << 8;
l += ((long)b[2] & 0xFF) << 16;
l += ((long)b[3] & 0xFF) << 24;

刚刚意识到:$所以我应该如何将这个无符号的小端发送给我的java进程以正确读取它?
hhafez

ay,我的意思是从头开始是lsb在4个字节的开头(这是一个无符号的32位int),所以我的意思是最低有效字节
hhafez

我也是从C-> Java而不是
Java-

只要您在最后三行中的0xFF之后删除分号,您的代码就可以正常工作。我自己编辑,但是更改少于6个字符。
Moose Morals

1
用了将近8年的时间,但最终有人发现了语法错误。感谢@MooseMorals :)
JonasElfström16年

12

这不可能对Java产生任何影响,因为没有(直接非API)将某些字节直接映射到Java中的int的方法。

每个执行此操作或类似操作的API都会精确地定义行为,因此您应该查找该API的文档。


3
哦,肯定有。二进制数学(&,|,<<等)在字节和整数上都可以正常工作。取任意字节并将其粘贴为整数非常容易。
爱马仕(Herms)

8
但是,如果这样做,您仍然无法确定JVM在内部使用什么耐久性。
达伦(Darron)

4
是的,但是即使在那儿也没有直接映射。您正在使用的算法完全可以满足您的要求,没有歧义。在C语言中,您总是可以将“ byte *”强制转换为“ long *”并取消引用。然后,您将不得不考虑耐力。在Java中,没有直接的,模棱两可的方法可以做到这一点。
约阿希姆·绍尔

知道了 您是在谈论转换,而不是二进制数学。是的,在那种情况下你是对的。
爱马仕(Herms)

10
+1为“查找文档”,但请注意:第一句话不再正确,因为如今NIO软件包提供了ByteBuffer,它可以将字节映射到基元,并且可以在其中更改字节顺序。参见ByteBufferByteOrder
2011年

3

我将一一读取字节,并将它们组合成一个值。这样,您可以控制字节顺序,并且通信过程是透明的。


想评论一下您为什么拒绝我吗?
Wouter Lievens

因为即使我在哪里分别读取每个字节,发送的字节的字节顺序也不正确,所以我需要将其转换
hhafez

23
字节的字节序?这他妈到底是什么?单词对字节顺序很敏感,单个字节则不然。
Wouter Lievens

3
@hhafez这是不对的,如果您逐字节读取字节,那么字节就没有字节性,程序员需要负责将字节分配到正确的位置。这正是DataInputStream所做的,它只是在幕后以大字节序的方式将字节组装在一起。

2
@WouterLievens:我遇到了一些I / O设备(例如实时时钟芯片),无论出于何种原因,它们都会以位反转格式发送数据;从它们接收数据后,有必要反转每个字节中的位。不过,我同意你的看法,字节的字节序通常不是问题,除非必须处理特殊设计的特殊硬件。
2013年

3

如果它符合您使用的协议,请考虑使用行为非常明确的DataInputStream 。


1
如果他的协议使用相同的字节序,则他只能这样做。
Wouter Lievens

我修复了该链接,并将其更改为指向当前版本的Java 9。不过,相关的API是在Java 1.0中引入的。
Jens Bannmann '17

2

如上所述,Java是“大端”。这意味着如果您检查内存(至少在Intel CPU上),则int的MSB在左侧。对于所有Java整数类型,符号位也在MSB中。
从“ Little-endian”系统存储的二进制文件中读取4字节无符号整数需要用Java进行一些修改。DataInputStream的readInt()需要Big-endian格式。
这是一个将四个字节的无符号值(如HexEdit显示为01 00 00 00)读为值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;        
 }

“上述”是指什么?SO答案的显示顺序可能有所不同。
LarsH

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.