web-dev-qa-db-fra.com

Convertir un tableau d'octets/Uint8 en Int dans Swift

Comment convertir un tableau de 4 octets en Int correspondant?

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

Exemple:

Contribution:

\0\0\0\x0e

Sortie:

14

Certains codes trouvés sur Internet qui ne fonctionnent pas:

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

Il y a deux problèmes:

  • Int est un entier de 64 bits sur les plates-formes 64 bits, vos données d'entrée n'ont que 32 bits.
  • Int utilise une représentation little-endian sur toutes les plateformes Swift actuelles, votre entrée est big-endian.

Cela étant dit, ce qui suit fonctionnerait:

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

Ou en utilisant Data dans Swift 3:

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

Avec certains points magiques du tampon, vous pouvez éviter l’intermédiaire Copier dans un objet 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

Pour une version Swift 3 de cette approche, voir la réponse de ambientlight.

31
Martin R

Dans Swift 3, il est maintenant un peu plus verbeux

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)
14
ambientlight

Je pense que la réponse de Martin est meilleure que cela, mais je veux tout de même poster la mienne. Toute suggestion serait vraiment utile.

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
7
Jerry

Il y a de bonnes réponses ici, ce qui est vraiment agréable à voir ^^ Toutefois, si vous souhaitez éviter toute interaction avec l'API d'interopérabilité C de Swift, je vous recommande de jeter un coup d'œil à mon exemple. C'est aussi générique pour toutes les tailles de types de données. Notez que MemoryLayout est uniquement utilisé pour un contrôle d'intégrité.

Code:

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)
    }
}

Exemple d'utilisation:

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

Pour ceux qui préfèrent le faire à l'ancienne, voici un ensemble de méthodes pour obtenir les valeurs int d'un tableau d'octets. Ceci est destiné aux situations où un tableau d'octets contenant différents types de données est traité séquentiellement.

/// 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
   }
}

Ceci est un extrait d'une classe plus large qui inclut des méthodes d'extraction de chaînes et d'autres types de données. Voir aussi ici: https://stackoverflow.com/a/41592206/253938

0
RenniePet