在Swift中将双字节UInt8数组转换为UInt16

在Swift中将双字节UInt8数组转换为UInt16,swift,Swift,使用Swift,我想将uint8_t数组中的字节转换为整数 “C”示例: char字节[2]={0x01,0x02}; NSData*data=[NSData dataWithBytes:字节长度:2]; NSLog(@“数据:%@”,数据);//数据: uint16_t value2=*(uint16_t*)data.bytes; NSLog(@“value2:%i”,value2);//价值2:513 快速尝试: let bytes:[UInt8] = [0x01, 0x02] print

使用Swift,我想将uint8_t数组中的字节转换为整数

“C”示例:

char字节[2]={0x01,0x02};
NSData*data=[NSData dataWithBytes:字节长度:2];
NSLog(@“数据:%@”,数据);//数据:
uint16_t value2=*(uint16_t*)data.bytes;
NSLog(@“value2:%i”,value2);//价值2:513
快速尝试:

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
let字节:[UInt8]=[0x01,0x02]
println(“字节:\(字节)”)//字节:[1,2]
let data=NSData(字节:字节,长度:2)
println(“数据:\(数据)”)//数据:
让integer1=*data.bytes//此操作失败
设integer2=*data.bytes为UInt16//此操作失败
让dataBytePointer=UnsafePointer(data.bytes)
设integer3=dataBytePointer为UInt16//此操作失败
设integer4=*dataBytePointer为UInt16//此操作失败
让integer5=*dataBytePointer//此操作失败
在Swift中,从UInt8数组创建UInt16值的正确语法或代码是什么


我对NSData版本感兴趣,正在寻找不使用临时阵列的解决方案

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

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

如果要通过
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
怎么样

let bytes:[UInt8] = [0x01, 0x02]
let result = (UInt16(bytes[1]) << 8) + UInt16(bytes[0])
let字节:[UInt8]=[0x01,0x02]
让结果=(UInt16(字节[1])UInt{

断言(byteArray.count如果字节位于您可以执行的
NSData
对象中(假设
data:NSData
):

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


编辑:如果从缓冲区的开头开始,则无需使用范围)

假设使用小尾端编码

要从[UInt8]转换为UInt16,可以执行以下操作

var x: [UInt8] = [0x01, 0x02]
var y: UInt16 = 0
y += UInt16(x[1]) << 0o10
y += UInt16(x[0]) << 0o00
变量x:[UInt8]=[0x01,0x02] 变量y:UInt16=0
y+=UInt16(x[1])Martin R的答案非常好,并且针对beta 6进行了很好的更新。 但是,如果需要获取不在缓冲区开头的字节,建议的
withMemoryRebound
方法不提供重新绑定的范围。 我的解决方案是,例如,从阵列中选择第二个UInt16:

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

Swift 5或更高版本中可以使用
withUnsafeBytes{$0.load(as:UInt16.self)}将字节
[UInt8]
转换为
UInt16

加载为
UInt16

let uint16 = bytes.withUnsafeBytes { $0.load(as: UInt16.self) }    // 513 

为了避免冗长,我们可以创建一个扩展
ContiguousBytes
的通用方法:

extension ContiguousBytes {
    func object<T>() -> T {
        withUnsafeBytes { $0.load(as: T.self) }
    }
}

要访问集合中任意位置的字节,请执行以下操作:

extension Data {
    func subdata<R: RangeExpression>(in range: R) -> Self where R.Bound == Index {
        subdata(in: range.relative(to: self) )
    }
    func object<T>(at offset: Int) -> T {
        subdata(in: offset...).object()
    }
}



关闭,这确实有效:
let a:UInt16=UInt16(字节[0])*256+UInt16(字节[1])
@Zaph我将复制粘贴您的代码,它肯定比我的更正确我对
NSData
版本感兴趣,但我正在寻找一个不使用临时数组的解决方案。@Zaph:哪个临时数组?也许
let u16=UnsafePointer(data.bytes).memory
是您要找的吗?这正是我要找的!谢谢!
让u16=UnsafePointer(data.bytes).memory
@Zaph请确保您确实有更好的性能,并且您确实需要它。使用不安全的代码最终可能会使您的性能更差,因为编译器可能会忘记您的代码的功能,并且无法用更高效的代码替换您的代码。@pqnet我不关心这个级别的性能l、 当测量结果显示需要并指出问题所在时,性能得到最好的解决。至于安全,我当然希望安全,请提供这样的解决方案。请记住,在这种情况下,以及同一类别中的许多其他原始数据字节接收时没有JSON、XML或其他更高级别的格式。是和
letb:UInt16=UInt16(数据字节指针[0])*256+UInt16(数据字节指针[1])
同样有效。非常不雅观,UInt32看起来更糟。为什么UInt32更糟?可以通过循环数组并按当前索引缩放移位量来组合多个字节。更糟的是,语句变得更长更复杂。如果只升到4,则无需泛化。只需在一行中编写公式,ma按部就班地写移位。如果你坚持使用一般形式,使用递归而不是循环,看起来会更好。@pqnet:我喜欢将其推广到2、4或8,以分别生成UInt16、UInt32或UInt64。我还打算将循环/函数实现作为对Zaph的一种回应,Zaph说当模式为o很明显,它几乎可以简单地自动化。我个人更喜欢它是一个全Swift的解决方案,尽管有人表示更喜欢基于NSData的解决方案。我非常喜欢将它保留在基础语言中,并避免不安全的指针构造。当然,像Swift这样的新语言有一种优雅的方式来转换在
NSData中接收的数据
到整数变量。这就是我要找的。是[0x01,0x02]0x0102的uint16还是0x0201?这取决于处理器的endianness。在java中是定义的。在C中是开放的。在Swift中我不知道。诀窍是
*(uint16)(uint8[2])
还存在地址对齐问题。@JoopEggen-Endian不是问题所在。更好的方法是对数据进行索引:
let u16=UnsafePointer(data.bytes)[index]
我希望Swift允许安全直接的操作,你能说是可选的吗?这仍然让人怀疑是否有字节是0,或者只有一个或没有。因此仍然需要进行长度检查。只需先进行长度检查,然后让
u16=UnsafePointer(data.bytes)[index]
也是安全的。一旦完成了长度检查,就可以简单地通过索引对数据进行进一步索引。@Zaph不管是什么人,这是你的代码。我不负责it@Zaph误会是两个人的错。对不起,我真的以为你在骗我。这是2049,但是
var x: [UInt8] = [0x01, 0x02]
var y: UInt16 = 0
y += UInt16(x[1]) << 0o10
y += UInt16(x[0]) << 0o00
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
var x: [UInt8] = [0x01, 0x02]
let y: UInt16 = reverse(x).reduce(UInt16(0)) {
    $0 << 0o10 + UInt16($1)
}
var x: [UInt8] = [0x01, 0x02, 0x03, 0x04]
let y: UInt32 = reverse(x).reduce(UInt32(0)) {
    $0 << 0o10 + UInt32($1)
}
var val: UInt16 = 0
let buf = UnsafeMutableBufferPointer(start: &val, count: 1)
_ = dat.copyBytes(to: buf, from: Range(2...3))
let bytes: [UInt8] = [1, 2]
let uint16 = bytes.withUnsafeBytes { $0.load(as: UInt16.self) }    // 513 
extension ContiguousBytes {
    func object<T>() -> T {
        withUnsafeBytes { $0.load(as: T.self) }
    }
}
let bytes: [UInt8] = [1, 2]
let uint16: UInt16 = bytes.object()    // 513
extension Data {
    func subdata<R: RangeExpression>(in range: R) -> Self where R.Bound == Index {
        subdata(in: range.relative(to: self) )
    }
    func object<T>(at offset: Int) -> T {
        subdata(in: offset...).object()
    }
}
extension Sequence where Element == UInt8  {
    var data: Data { .init(self) }
}
extension Collection where Element == UInt8, Index == Int {
    func object<T>(at offset: Int = 0) -> T {
        data.object(at: offset)
    }
}
let bytes: [UInt8] = [255, 255, 1, 2]
let uintMax: UInt16 = bytes.object()      // 65535 at offset zero
let uint16: UInt16 = bytes.object(at: 2)  // 513   at offset two