Convert a two byte UInt8 array to a UInt16 in Swift

匿名 (未验证) 提交于 2019-12-03 02:50:02

问题:

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

"C" Example:

char bytes[2] = {0x01, 0x02}; NSData *data = [NSData dataWithBytes:bytes length:2]; NSLog(@"data: %@", data); // data:   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:   let integer1 = *data.bytes // This fails let integer2 = *data.bytes as UInt16 // This fails  let dataBytePointer = UnsafePointer(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?

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

回答1:

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

let bytes:[UInt8] = [0x01, 0x02] println("bytes: \(bytes)") // bytes: [1, 2] let data = NSData(bytes: bytes, length: 2) print("data: \(data)") // data:   var u16 : UInt16 = 0 ; data.getBytes(&u16) // Or: let u16 = UnsafePointer(data.bytes).memory  println("u16: \(u16)") // u16: 513 

Alternatively:

let bytes:[UInt8] = [0x01, 0x02] let u16 = UnsafePointer(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):

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


回答2:

How about

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

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 


回答3:

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

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


回答4:

If the bytes are in an NSData object you may do (assume data: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.

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



回答5:

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:

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


回答6:

Assuming little endian encoding.

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

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

For conversion to UInt32, this pattern extends to

var x: [UInt8] = [0x01, 0x02, 0x03, 0x04] var y: UInt32 = 0 y += UInt32(x[3]) 

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

This can be reduced to the following for UInt16:

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

and to the following for UInt32:

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

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



回答7:

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

Swift 3 or later

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 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!