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