Преобразование массива bytes/Uint8 в Int в Swift

как преобразовать 4-байтовый массив в соответствующий Int?

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

пример:

вход:

x0e

выход:

14

некоторый код, который я нашел в интернете, который не работает:

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

5 ответов


есть две проблемы:

  • Int 64-разрядное целое число на 64-разрядных платформах, ваши входные данные имеет только 32-разрядные.
  • Int использует представление little-endian на всех текущих платформах Swift, ваш вклад является 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

или через Data в Swift 3:

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

С некоторой магией указателя буфера вы можете избежать промежуточного копии NSData объект (Swift 2):

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

print(value) // 14

для версии Swift 3 этого подхода см. ответ ambientlight.


в Swift 3 Теперь немного более многословны:

let array : [UInt8] = [0, 0, 0, 0x0E]
let bigEndianValue = array.withUnsafeBufferPointer {
         (.baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1) {  })
}.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

здесь есть несколько хороших ответов, которые действительно приятно видеть ^^ Однако если вы хотите, чтобы избежать взаимодействия с C-совместимость с API SWIFT, то я рекомендую взглянуть на мой пример. Он также является универсальным для всех размеров типов данных. Обратите внимание, что MemoryLayout используется только для проверки вменяемости.

код:

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

        var value : UIntMax = 0

        for byte in bytes {
            value <<= 8
            value |= UIntMax(byte)
        }

        self.init(value)
    }
}

пример использования:

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

для тех, кто предпочитает делать это старомодным способом, вот набор методов для получения значений 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