在Swift中将bytes / UInt8数组转换为Int

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Swift中将bytes / UInt8数组转换为Int相关的知识,希望对你有一定的参考价值。

如何将4字节数组转换为相应的Int?

let array: [UInt8] ==> let value : Int

例:

Input:

\0\0\0\x0e

Output:

14

Some code I found on the internet that doesn't work:

let data = NSData(bytes: array, length: 4)
data.getBytes(&size, length: 4)
// the output to size is 184549376
答案

有两个问题:

  • Int是64位平台上的64位整数,输入数据只有32位。
  • Int在所有当前的Swift平台上使用little-endian表示,你的输入是big-endian。

据说以下内容可行:

let array : [UInt8] = [0, 0, 0, 0x0E]
var value : UInt32 = 0
let data = NSData(bytes: array, length: 4)
data.getBytes(&value, length: 4)
value = UInt32(bigEndian: value)

print(value) // 14

或者在Swift 3中使用Data

let array : [UInt8] = [0, 0, 0, 0x0E]
let data = Data(bytes: array)
let value = UInt32(bigEndian: data.withUnsafeBytes  $0.pointee )

使用一些缓冲区指针魔术,您可以避免中间复制到NSData对象(Swift 2):

let array : [UInt8] = [0, 0, 0, 0x0E]
var value = array.withUnsafeBufferPointer( 
     UnsafePointer<UInt32>($0.baseAddress).memory
)
value = UInt32(bigEndian: value)

print(value) // 14

对于此方法的Swift 3版本,请参阅环境光的答案。

另一答案

在Swift 3中,它现在更加冗长:

let array : [UInt8] = [0, 0, 0, 0x0E]
let bigEndianValue = array.withUnsafeBufferPointer 
         ($0.baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1)  $0 )
.pointee
let value = UInt32(bigEndian: bigEndianValue)
另一答案

我认为马丁的回答比这更好,但我仍想发布我的回答。任何建议都会非常有用。

let array : [UInt8] = [0, 0, 0, 0x0E]
var value : Int = 0
for byte in array 
    value = value << 8
    value = value | Int(byte)

print(value) // 14
另一答案

这里有一些很好的答案,非常高兴看到^^但是如果你想避免与Swift的C-interopability API进行交互,那么我建议你看看我的例子。对于所有数据类型大小,它也是通用的。请注意,MemoryLayout仅用于健全性检查。

码:

public extension UnsignedInteger 
    init(_ bytes: [UInt8]) 
        precondition(bytes.count <= MemoryLayout<Self>.size)

        var value: UInt64 = 0

        for byte in bytes 
            value <<= 8
            value |= UInt64(byte)
        

        self.init(value)
    

用法示例:

let someBytes = [UInt8](repeating: 0x42, count: 2)
let someValue = UInt16(someBytes)

对于小端支持,你需要for byte in bytes.reversed()

另一答案

当你不知道你的字节数组(或你的Data大小)的大小时,接受答案的问题就来了

它适用于let array : [UInt8] = [0, 0, 0x23, 0xFF]

但它不适用于let array : [UInt8] = [0x23, 0xFF] (因为它将被视为[0x23, 0xFF, 0, 0]

这就是为什么我喜欢@Jerry的那个,按位操作。

我已经制作了他的代码片段的功能版本。

let data = Data(bytes: [0x23, 0xFF])
let decimalValue = data.reduce(0)  v, byte in
    return v << 8 | Int(byte)

另一答案

针对Swift 5进行了更新,需要注意以下两点:

  • 由于[UInt8]存储在连续的内存区域中,因此无需将其转换为Data,指针可以直接访问所有字节。
  • Int的字节顺序目前在所有Apple平台上都是小端,但这在其他平台上并不保证。

说我们希望[0, 0, 0, 0x0e]转换为14。 (big-endian字节顺序)

let source: [UInt8] = [0, 0, 0, 0x0e]
let bigEndianUInt32 = source.withUnsafeBytes  $0.load(as: UInt32.self) 
let value = CFByteOrderGetCurrent() == CFByteOrder(CFByteOrderLittleEndian.rawValue)
    ? UInt32(bigEndian: bigEndianUInt32)
    : bigEndianUInt32
print(value) // 14
另一答案

对于那些喜欢用老式方式做的人,这里有一组从字节数组中获取int值的方法。这适用于按顺序处理包含各种数据的字节数组的情况。

/// Class which encapsulates a Swift byte array (an Array object with elements of type UInt8) and an
/// index into the array.
open class ByteArrayAndIndex 

   private var _byteArray : [UInt8]
   private var _arrayIndex = 0

   public init(_ byteArray : [UInt8]) 
      _byteArray = byteArray;
   

   /// Property to provide read-only access to the current array index value.
   public var arrayIndex : Int 
      get  return _arrayIndex 
   

   /// Property to calculate how many bytes are left in the byte array, i.e., from the index point
   /// to the end of the byte array.
   public var bytesLeft : Int 
      get  return _byteArray.count - _arrayIndex 
   

   /// Method to get a single byte from the byte array.
   public func getUInt8() -> UInt8 
      let returnValue = _byteArray[_arrayIndex]
      _arrayIndex += 1
      return returnValue
   

   /// Method to get an Int16 from two bytes in the byte array (little-endian).
   public func getInt16() -> Int16 
      return Int16(bitPattern: getUInt16())
   

   /// Method to get a UInt16 from two bytes in the byte array (little-endian).
   public func getUInt16() -> UInt16 
      let returnValue = UInt16(_byteArray[_arrayIndex]) |
                        UInt16(_byteArray[_arrayIndex + 1]) << 8
      _arrayIndex += 2
      return returnValue
   

   /// Method to get a UInt from three bytes in the byte array (little-endian).
   public func getUInt24() -> UInt 
      let returnValue = UInt(_byteArray[_arrayIndex]) |
                        UInt(_byteArray[_arrayIndex + 1]) << 8 |
                        UInt(_byteArray[_arrayIndex + 2]) << 16
      _arrayIndex += 3
      return returnValue
   

   /// Method to get an Int32 from four bytes in the byte array (little-endian).
   public func getInt32() -> Int32 
      return Int32(bitPattern: getUInt32())
   

   /// Method to get a UInt32 from four bytes in the byte array (little-endian).
   public func getUInt32() -> UInt32 
      let returnValue = UInt32(_byteArray[_arrayIndex]) |
                        UInt32(_byteArray[_arrayIndex + 1]) << 8 |
                        UInt32(_byteArray[_arrayIndex + 2]) << 16 |
                        UInt32(_byteArray[_arrayIndex + 3]) << 24
      _arrayIndex += 4
      return returnValue
   

   /// Method to get an Int64 from eight bytes in the byte array (little-endian).
   public func getInt64() -> Int64 
      return Int64(bitPattern: getUInt64())
   

   /// Method to get a UInt64 from eight bytes in the byte array (little-endian).
   public func getUInt64() -> UInt64 
      let returnValue = UInt64(_byteArray[_arrayIndex]) |
                        UInt64(_byteArray[_arrayIndex + 1]) << 8 |
                        UInt64(_byteArray[_arrayIndex + 2]) << 16 |
                        UInt64(_byteArray[_arrayIndex + 3]) << 24 |
                        UInt64(_byteArray[_arrayIndex + 4]) << 32 |
                        UInt64(_byteArray[_arrayIndex + 5]) << 40 |
                        UInt64(_byteArray[_arrayIndex + 6]) << 48 |
                        UInt64(_byteArray[_arrayIndex + 7]) << 56
      _arrayIndex += 8
      return returnValue
   

这是一个较大类的摘录,包括提取字符串和其他类型数据的方法。另见:https://stackoverflow.com/a/41592206/253938

以上是关于在Swift中将bytes / UInt8数组转换为Int的主要内容,如果未能解决你的问题,请参考以下文章

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

swift 在swift中将uint8转换为字符串

如何在 Swift 2.3 中将 UInt8 转换为 Anyobject

如何在 Swift 3 中将 [UInt8] 数组复制到 C 指针?

在 Swift 中将有符号转换为无符号

如何将 bitset 转换为 bytes/uint8 数组?