如何从 Kotlin JVM 中的字节数组中获取无符号整数?
How to get an unsigned integer from a byte array in Kotlin JVM?
Kotlin 1.3 引入了 unsigned integer types,但我似乎无法弄清楚如何从 Kotlin JVM 中的 ByteArray
获取无符号整数。
Kotlin Native 有一个方便的 ByteArray.getUIntAt()
方法,但这对 Kotlin JVM 不存在。
val bytes: ByteArray = byteArrayOf(1, 1, 1, 1)
val uint: UInt // = ???
我在这里有哪些选择?有没有比使用 ByteBuffer
或位移位更优雅的方法?
如评论中所述,Kotlin 的 JVM 版本中没有开箱即用的解决方案。与 Kotlin/Native 功能相同的扩展功能可能如下所示:
fun ByteArray.getUIntAt(idx: Int) =
((this[idx].toUInt() and 0xFFu) shl 24) or
((this[idx + 1].toUInt() and 0xFFu) shl 16) or
((this[idx + 2].toUInt() and 0xFFu) shl 8) or
(this[idx + 3].toUInt() and 0xFFu)
fun main(args: Array<String>) {
// 16843009
println(byteArrayOf(1, 1, 1, 1).getUIntAt(0))
// 4294967295, which is UInt.MAX_VALUE
println(byteArrayOf(-1, -1, -1, -1).getUIntAt(0))
}
为了扩展@Alexander 的 ,我编写了一个版本,它接受少于四个值的 ByteArray。我发现这在解析混合有符号和无符号整数的 ByteArrays 时特别有用(在我的例子中是蓝牙特征更新通知)
我需要分割成子数组。
fun ByteArray.fromUnsignedBytesToInt(): Int {
//Note: UInt is always 32 bits (4 bytes) regardless of platform architecture
//See https://kotlinlang.org/docs/basic-types.html#unsigned-integers
val bytes = 4
val paddedArray = ByteArray(bytes)
for (i in 0 until bytes-this.size) paddedArray[i] = 0
for (i in bytes-this.size until paddedArray.size) paddedArray[i] = this[i-(bytes-this.size)]
return (((paddedArray[0].toULong() and 0xFFu) shl 24) or
((paddedArray[1].toULong() and 0xFFu) shl 16) or
((paddedArray[2].toULong() and 0xFFu) shl 8) or
(paddedArray[3].toULong() and 0xFFu)).toInt()
}
下面的测试 class 证实了预期值:
import org.junit.Test
import org.junit.Assert.*
internal class ByteArrayExtKtTest {
@Test
fun testAsUnsignedToIntTwoBytes() {
val bytes = byteArrayOf (0x0A.toByte(), 0xBA.toByte())
assertEquals(2746, bytes.fromUnsignedBytesToInt())
}
@Test
fun testAsUnsignedToIntFourBytes() {
val bytes = byteArrayOf(1,1,1,1)
assertEquals(16843009, bytes.fromUnsignedBytesToInt())
}
}
Kotlin 1.3 引入了 unsigned integer types,但我似乎无法弄清楚如何从 Kotlin JVM 中的 ByteArray
获取无符号整数。
Kotlin Native 有一个方便的 ByteArray.getUIntAt()
方法,但这对 Kotlin JVM 不存在。
val bytes: ByteArray = byteArrayOf(1, 1, 1, 1)
val uint: UInt // = ???
我在这里有哪些选择?有没有比使用 ByteBuffer
或位移位更优雅的方法?
如评论中所述,Kotlin 的 JVM 版本中没有开箱即用的解决方案。与 Kotlin/Native 功能相同的扩展功能可能如下所示:
fun ByteArray.getUIntAt(idx: Int) =
((this[idx].toUInt() and 0xFFu) shl 24) or
((this[idx + 1].toUInt() and 0xFFu) shl 16) or
((this[idx + 2].toUInt() and 0xFFu) shl 8) or
(this[idx + 3].toUInt() and 0xFFu)
fun main(args: Array<String>) {
// 16843009
println(byteArrayOf(1, 1, 1, 1).getUIntAt(0))
// 4294967295, which is UInt.MAX_VALUE
println(byteArrayOf(-1, -1, -1, -1).getUIntAt(0))
}
为了扩展@Alexander 的
fun ByteArray.fromUnsignedBytesToInt(): Int {
//Note: UInt is always 32 bits (4 bytes) regardless of platform architecture
//See https://kotlinlang.org/docs/basic-types.html#unsigned-integers
val bytes = 4
val paddedArray = ByteArray(bytes)
for (i in 0 until bytes-this.size) paddedArray[i] = 0
for (i in bytes-this.size until paddedArray.size) paddedArray[i] = this[i-(bytes-this.size)]
return (((paddedArray[0].toULong() and 0xFFu) shl 24) or
((paddedArray[1].toULong() and 0xFFu) shl 16) or
((paddedArray[2].toULong() and 0xFFu) shl 8) or
(paddedArray[3].toULong() and 0xFFu)).toInt()
}
下面的测试 class 证实了预期值:
import org.junit.Test
import org.junit.Assert.*
internal class ByteArrayExtKtTest {
@Test
fun testAsUnsignedToIntTwoBytes() {
val bytes = byteArrayOf (0x0A.toByte(), 0xBA.toByte())
assertEquals(2746, bytes.fromUnsignedBytesToInt())
}
@Test
fun testAsUnsignedToIntFourBytes() {
val bytes = byteArrayOf(1,1,1,1)
assertEquals(16843009, bytes.fromUnsignedBytesToInt())
}
}