【问题标题】:Does Java read integers in little endian or big endian?Java 是以小端还是大端读取整数?
【发布时间】:2010-09-26 14:49:26
【问题描述】:

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

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

追问:如果Java端的endian和发送的不一样,如何相互转换?

【问题讨论】:

  • 这是我的助记符,所以我不会忘记:Java 不是硬件而是虚拟的,是互联网的语言。 网络字节顺序big endian。因此,Java 是 big endian

标签: java endianness


【解决方案1】:

使用网络字节顺序(大端),这与 Java 使用的相同。查看 C 语言中不同翻译器的 man htons。

【讨论】:

  • 我现在不在我的 linux 机器上,但 htons 是标准库之一吗?
  • 根据h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/…它是标准c库的一部分,是的
  • htons 几乎在任何地方都可用,但它不在 ISO C 中。
  • 如果您必须使用网络字节顺序以外的其他内容,那么您可以使用按位运算符自行开发或使用各种版本的 java.nio.Buffer
  • 根据它的手册页,它是在 POSIX.1 中定义的,所以它应该几乎无处不在。而且我似乎记得在 Win32 中使用过它,所以它也不只是在 POSIX 系统上。
【解决方案2】:

我是通过 Google 偶然发现的,得到的答案是 Java 是 big endian

阅读回复后,我想指出字节确实有一个字节序,但幸运的是,如果您只处理过“主流”微处理器,您不太可能遇到过它,例如英特尔、摩托罗拉、和 Zilog 都同意他们的 UART 芯片的移位方向,并且在他们的 CPU 中一个字节的 MSB 将是2**7 和 LSB 将是2**0(我使用 FORTRAN 幂符号来强调这些东西有多古老 :)) .

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

【讨论】:

  • 伟大的洞察力!我有这个问题,但在网络上没有答案。
  • 如果其中任何一个是公开的,您能否链接您正在谈论的 NASA 技术简报(以及可能的航天飞机位串行下行链路数据)?会很有趣,我从来没有见过这样的东西。
  • 按位字节序也适用于使用某种形式的霍夫曼编码(即所有这些)的压缩格式。为了更有趣,JPEG 是“按位大端”(即最高有效位是“第一个”位),LZ 是“按位小端”。我曾经研究过一种专有的压缩格式,它在后台使用了这两种格式。哦,那很有趣...
  • 从比特开始,很长一段时间我都认为这是字节序。
【解决方案3】:

Java 中没有无符号整数。所有整数都是有符号的并且是大端的。

在 C 端,每个字节的开头都有 tne LSB,左边是 MSB。

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

从无符号字节转换为 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 进程以正确读取它?
  • 我的意思是开头是 lsb 在 4 个字节的开头(它是一个无符号的 32 位 int )所以我的意思是最低有效字节
  • 另外我正在从 C 转换 -> Java 而不是从 Java -> C :)
  • 您的代码工作正常,只要您在最后三行中删除 0xFF 之后的分号即可。我会自己编辑,但更改的字符数少于 6 个。
  • 花了将近 8 年的时间,终于有人发现了语法错误。谢谢@MooseMorals :)
【解决方案4】:

这不会影响 Java 中的任何内容,因为在 Java 中没有(直接的非 API)方法可以将某些字节直接映射到 int。

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

【讨论】:

  • 哦,当然有。二进制数学(&、|、
  • 但是如果你这样做,你仍然无法分辨你的 JVM 内部使用的是什么字节序。
  • 是的,但即使在那里你也不是直接映射。您正在使用的算术完全按照您所说的进行,没有歧义。在 C 中,您总是可以将“byte*”转换为“long*”并取消引用它。然后你必须关心字节序。在 Java 中,没有直接的、模棱两可的方式来做到这一点。
  • 啊,我明白了。你说的是演员阵容,而不是二进制数学。是的,在这种情况下你是对的。
  • +1 用于“查找文档”,但注意:第一句不再正确,因为现在 NIO 包提供 ByteBuffer它可以将字节映射到原语,并且您可以在其中更改字节顺序。见ByteBufferByteOrder
【解决方案5】:

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

【讨论】:

  • 想评论一下你为什么要投票给我吗?
  • 因为即使我在哪里单独读取每个字节,发送的字节的字节序也不正确,所以我需要转换它
  • 字节的字节序?这他妈到底是什么?单词对字节顺序敏感,单个字节不敏感。
  • @hhafez 这不是真的,就我们需要关注的字节而言,如果您逐字节读取,则您,程序员负责将字节分配到正确的位置。这正是 DataInputStream 所做的,它只是在底层以大端方式将字节组装在一起。
  • @WouterLievens:我遇到过一些 I/O 设备(例如实时时钟芯片),无论出于何种原因,它们以位反转格式发送数据;从它们接收到数据后,有必要反转每个字节中的位。不过,我同意你的观点,字节的字节序通常不是问题,除非必须处理特定设计奇特的硬件。
【解决方案6】:

如果它适合您使用的协议,请考虑使用 DataInputStream,其行为为 very well defined

【讨论】:

  • 只有当他的协议使用相同的字节序时,他才能这样做。
  • 我修复了链接,并将其更改为指向当前版本的 Java 9。不过,有问题的 API 是在 Java 1.0 中引入的。
【解决方案7】:

如上所述,Java 是“大端”。这意味着如果您检查内存(至少在 Intel CPU 上),则 int 的 MSB 位于左侧。对于所有 Java 整数类型,符号位也在 MSB 中。
从“Little-endian”系统存储的二进制文件中读取 4 字节无符号整数需要在 Java 中进行一些调整。 DataInputStream 的 readInt() 需要大端格式。
这是一个将四字节无符号值(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 答案的显示顺序可能会有所不同。
【解决方案8】:

【讨论】:

  • 这是关于字节码指令的字节序,而不是运行时数据的字节序。
  • 我投了赞成票。这个 sn-p byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array(); 产生了一个 byte 数组,它与我的 C/C++ 产生的相反。因此,Java的big endianness即使在运行时的数据中也会生效。
【解决方案9】:

恕我直言,没有为 java 定义字节顺序。字节序是硬件之一,但 java 是高级别的,隐藏了硬件,所以你不必担心。

唯一与字节序相关的特性是 java lib 如何将 int 和 long 映射到 byte[](反之亦然)。它采用 Big-Endian,这是最易读和最自然的:

int i=0xAABBCCDD

映射到

byte[] b={0xAA,0xBB,0xCC,0xDD}

【讨论】:

    猜你喜欢
    • 2010-09-18
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2011-05-10
    • 2013-02-27
    • 2011-02-06
    相关资源
    最近更新 更多