在Swift中将两个字节的UInt8数组转换为UInt16。

时间:2022-05-26 21:15:20

With Swift I want to convert bytes from a uint8_t array to an integer.

通过Swift,我希望将字节从uint8_t数组转换为整数。

"C" Example:

“C”的例子:

char bytes[2] = {0x01, 0x02};
NSData *data = [NSData dataWithBytes:bytes length:2];
NSLog(@"data: %@", data); // data: <0102>

uint16_t value2 = *(uint16_t *)data.bytes;
NSLog(@"value2: %i", value2); // value2: 513

Swift Attempt:

斯威夫特的尝试:

let bytes:[UInt8] = [0x01, 0x02]
println("bytes: \(bytes)") // bytes: [1, 2]
let data = NSData(bytes: bytes, length: 2)
println("data: \(data)") // data: <0102>

let integer1 = *data.bytes // This fails
let integer2 = *data.bytes as UInt16 // This fails

let dataBytePointer = UnsafePointer<UInt16>(data.bytes)
let integer3 = dataBytePointer as UInt16 // This fails
let integer4 = *dataBytePointer as UInt16 // This fails
let integer5 = *dataBytePointer // This fails

What is the correct syntax or code to create a UInt16 value from a UInt8 array in Swift?

在Swift中从UInt8数组中创建UInt16值的正确语法或代码是什么?

I am interested in the NSData version and am looking for a solution that does not use a temp array.

我对NSData版本感兴趣,并且正在寻找一个不使用temp数组的解决方案。

7 个解决方案

#1


38  

If you want to go via NSData then it would work like this:

如果你想通过NSData,它会这样工作:

let bytes:[UInt8] = [0x01, 0x02]
println("bytes: \(bytes)") // bytes: [1, 2]
let data = NSData(bytes: bytes, length: 2)
print("data: \(data)") // data: <0102>

var u16 : UInt16 = 0 ; data.getBytes(&u16)
// Or:
let u16 = UnsafePointer<UInt16>(data.bytes).memory

println("u16: \(u16)") // u16: 513

Alternatively:

另外:

let bytes:[UInt8] = [0x01, 0x02]
let u16 = UnsafePointer<UInt16>(bytes).memory
print("u16: \(u16)") // u16: 513

Both variants assume that the bytes are in the host byte order.

这两个变体都假定字节位于主机字节顺序。

Update for Swift 3 (Xcode 8):

更新Swift 3 (Xcode 8):

let bytes: [UInt8] = [0x01, 0x02]
let u16 = UnsafePointer(bytes).withMemoryRebound(to: UInt16.self, capacity: 1) {
    $0.pointee
}
print("u16: \(u16)") // u16: 513

#2


5  

How about

如何

let bytes:[UInt8] = [0x01, 0x02]
let result = (UInt16(bytes[1]) << 8) + UInt16(bytes[0])

With a loop, this easily generalizes to larger byte arrays, and it can be wrapped in a function for readability:

对于一个循环,这很容易推广到更大的字节数组,并且它可以被封装在一个用于可读性的函数中:

let bytes:[UInt8] = [0x01, 0x02, 0x03, 0x04]

func bytesToUInt(byteArray: [UInt8]) -> UInt {
  assert(byteArray.count <= 4)
  var result: UInt = 0
  for idx in 0..<(byteArray.count) {
    let shiftAmount = UInt((byteArray.count) - idx - 1) * 8
    result += UInt(byteArray[idx]) << shiftAmount
  }
  return result
}

println(bytesToUInt(bytes))    // result is 16909060

#3


3  

I don't know the syntax for swift, but what about something like:

我不知道swift的语法,但是像这样的:

let a:UInt16 = UInt16(bytes[0]) * 256 + UInt16(bytes[1])

#4


3  

If the bytes are in an NSData object you may do (assume data:NSData):

如果字节位于NSData对象中,您可以这样做(假设数据:NSData):

var number: UInt16 = 0
data.getBytes(&number, length: sizeof(UInt16))

The getBytes method writes up to two bytes in the memory location of number (similar to C's memcpy. This won't crash your app if data hasn't enough bytes.

getBytes方法在内存位置(类似于C的memcpy)中写入最多两个字节。如果数据没有足够的字节,这不会使你的应用崩溃。

(edit: no need to use range if starting from beginning of buffer)

(编辑:如果从缓冲区开始就不需要使用范围)

#5


2  

Martin R's answer is great and nicely updated for beta 6. However, if you need to get at bytes that are not at the start of your buffer the proposed withMemoryRebound method does not offer a range to rebind from. My solution to this, eg. pick out the second UInt16 from an array was:

马丁·R的回答很好,并且很好地更新了测试版6。但是,如果您需要获取不是在缓冲区开始处的字节,那么建议的withmemory反弹方法不会提供一个范围来重新绑定。我的解决办法是。从数组中选择第二个UInt16是:

var val: UInt16 = 0
let buf = UnsafeMutableBufferPointer(start: &val, count: 1)
_ = dat.copyBytes(to: buf, from: Range(2...3))

#6


0  

Assuming little endian encoding.

假设小端字节编码。

To convert to UInt16 from [UInt8], you can do something like

要从[UInt8]转换为UInt16,您可以执行类似的操作。

var x: [UInt8] = [0x01, 0x02]
var y: UInt16 = 0
y += UInt16(x[1]) << 0o10
y += UInt16(x[0]) << 0o00

For conversion to UInt32, this pattern extends to

对于转换到UInt32,此模式扩展到。

var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
var y: UInt32 = 0
y += UInt32(x[3]) << 0o30
y += UInt32(x[2]) << 0o20
y += UInt32(x[1]) << 0o10
y += UInt32(x[0]) << 0o00

Octal representation of the shift amount gives a nice indication on how many full bytes are shifted (8 becomes 0o10, 16 becomes 0o20 etc).

移位量的八进制表示可以很好地说明有多少个字节被移动(8变成0o10, 16变成0o20等等)。

This can be reduced to the following for UInt16:

这可以简化为UInt16:

var x: [UInt8] = [0x01, 0x02]
let y: UInt16 = reverse(x).reduce(UInt16(0)) {
    $0 << 0o10 + UInt16($1)
}

and to the following for UInt32:

以下为UInt32:

var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
let y: UInt32 = reverse(x).reduce(UInt32(0)) {
    $0 << 0o10 + UInt32($1)
}

The reduced version also works for UInt64, and also handles values where the byte encoding does not use all bytes, like [0x01, 0x02, 0x03]

reduce版本也适用于UInt64,并处理字节编码不使用所有字节的值,比如[0x01、0x02、0x03]

#7


0  

In Swift 3 or later you can convert the bytes [UInt8] to Data and get the UInt16 value using withUnsafeBytes { $0.pointee }

在Swift 3或之后,您可以将字节(UInt8)转换为数据,并使用withUnsafeBytes{$0来获取UInt16值。指针数据}

Swift 3 or later

斯威夫特3或更高

extension Data {
    var uint16: UInt16 {
        return withUnsafeBytes { $0.pointee }
    }
}

extension Array where Element == UInt8 {
    var data: Data { return Data(self) }
}

let bytes: [UInt8] = [1, 2]
let uint16 = bytes.data.uint16
print(uint16) // 513

#1


38  

If you want to go via NSData then it would work like this:

如果你想通过NSData,它会这样工作:

let bytes:[UInt8] = [0x01, 0x02]
println("bytes: \(bytes)") // bytes: [1, 2]
let data = NSData(bytes: bytes, length: 2)
print("data: \(data)") // data: <0102>

var u16 : UInt16 = 0 ; data.getBytes(&u16)
// Or:
let u16 = UnsafePointer<UInt16>(data.bytes).memory

println("u16: \(u16)") // u16: 513

Alternatively:

另外:

let bytes:[UInt8] = [0x01, 0x02]
let u16 = UnsafePointer<UInt16>(bytes).memory
print("u16: \(u16)") // u16: 513

Both variants assume that the bytes are in the host byte order.

这两个变体都假定字节位于主机字节顺序。

Update for Swift 3 (Xcode 8):

更新Swift 3 (Xcode 8):

let bytes: [UInt8] = [0x01, 0x02]
let u16 = UnsafePointer(bytes).withMemoryRebound(to: UInt16.self, capacity: 1) {
    $0.pointee
}
print("u16: \(u16)") // u16: 513

#2


5  

How about

如何

let bytes:[UInt8] = [0x01, 0x02]
let result = (UInt16(bytes[1]) << 8) + UInt16(bytes[0])

With a loop, this easily generalizes to larger byte arrays, and it can be wrapped in a function for readability:

对于一个循环,这很容易推广到更大的字节数组,并且它可以被封装在一个用于可读性的函数中:

let bytes:[UInt8] = [0x01, 0x02, 0x03, 0x04]

func bytesToUInt(byteArray: [UInt8]) -> UInt {
  assert(byteArray.count <= 4)
  var result: UInt = 0
  for idx in 0..<(byteArray.count) {
    let shiftAmount = UInt((byteArray.count) - idx - 1) * 8
    result += UInt(byteArray[idx]) << shiftAmount
  }
  return result
}

println(bytesToUInt(bytes))    // result is 16909060

#3


3  

I don't know the syntax for swift, but what about something like:

我不知道swift的语法,但是像这样的:

let a:UInt16 = UInt16(bytes[0]) * 256 + UInt16(bytes[1])

#4


3  

If the bytes are in an NSData object you may do (assume data:NSData):

如果字节位于NSData对象中,您可以这样做(假设数据:NSData):

var number: UInt16 = 0
data.getBytes(&number, length: sizeof(UInt16))

The getBytes method writes up to two bytes in the memory location of number (similar to C's memcpy. This won't crash your app if data hasn't enough bytes.

getBytes方法在内存位置(类似于C的memcpy)中写入最多两个字节。如果数据没有足够的字节,这不会使你的应用崩溃。

(edit: no need to use range if starting from beginning of buffer)

(编辑:如果从缓冲区开始就不需要使用范围)

#5


2  

Martin R's answer is great and nicely updated for beta 6. However, if you need to get at bytes that are not at the start of your buffer the proposed withMemoryRebound method does not offer a range to rebind from. My solution to this, eg. pick out the second UInt16 from an array was:

马丁·R的回答很好,并且很好地更新了测试版6。但是,如果您需要获取不是在缓冲区开始处的字节,那么建议的withmemory反弹方法不会提供一个范围来重新绑定。我的解决办法是。从数组中选择第二个UInt16是:

var val: UInt16 = 0
let buf = UnsafeMutableBufferPointer(start: &val, count: 1)
_ = dat.copyBytes(to: buf, from: Range(2...3))

#6


0  

Assuming little endian encoding.

假设小端字节编码。

To convert to UInt16 from [UInt8], you can do something like

要从[UInt8]转换为UInt16,您可以执行类似的操作。

var x: [UInt8] = [0x01, 0x02]
var y: UInt16 = 0
y += UInt16(x[1]) << 0o10
y += UInt16(x[0]) << 0o00

For conversion to UInt32, this pattern extends to

对于转换到UInt32,此模式扩展到。

var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
var y: UInt32 = 0
y += UInt32(x[3]) << 0o30
y += UInt32(x[2]) << 0o20
y += UInt32(x[1]) << 0o10
y += UInt32(x[0]) << 0o00

Octal representation of the shift amount gives a nice indication on how many full bytes are shifted (8 becomes 0o10, 16 becomes 0o20 etc).

移位量的八进制表示可以很好地说明有多少个字节被移动(8变成0o10, 16变成0o20等等)。

This can be reduced to the following for UInt16:

这可以简化为UInt16:

var x: [UInt8] = [0x01, 0x02]
let y: UInt16 = reverse(x).reduce(UInt16(0)) {
    $0 << 0o10 + UInt16($1)
}

and to the following for UInt32:

以下为UInt32:

var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
let y: UInt32 = reverse(x).reduce(UInt32(0)) {
    $0 << 0o10 + UInt32($1)
}

The reduced version also works for UInt64, and also handles values where the byte encoding does not use all bytes, like [0x01, 0x02, 0x03]

reduce版本也适用于UInt64,并处理字节编码不使用所有字节的值,比如[0x01、0x02、0x03]

#7


0  

In Swift 3 or later you can convert the bytes [UInt8] to Data and get the UInt16 value using withUnsafeBytes { $0.pointee }

在Swift 3或之后,您可以将字节(UInt8)转换为数据,并使用withUnsafeBytes{$0来获取UInt16值。指针数据}

Swift 3 or later

斯威夫特3或更高

extension Data {
    var uint16: UInt16 {
        return withUnsafeBytes { $0.pointee }
    }
}

extension Array where Element == UInt8 {
    var data: Data { return Data(self) }
}

let bytes: [UInt8] = [1, 2]
let uint16 = bytes.data.uint16
print(uint16) // 513