38

How to convert a 4-bytes array into the corresponding Int?

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

Example:

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
2
  • @MartinR the output is wrong, it is a real big number Commented Sep 24, 2015 at 20:09
  • @MartinR Thanks for replying on my other posts. But so far none of them are actually solved. Commented Sep 24, 2015 at 20:10

6 Answers 6

55

There are two problems:

  • Int is a 64-bit integer on 64-bit platforms, your input data has only 32-bit.
  • Int uses a little-endian representation on all current Swift platforms, your input is big-endian.

That being said the following would work:

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

Or using Data in Swift 3:

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

With some buffer pointer magic you can avoid the intermediate copy to an NSData object (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

For a Swift 3 version of this approach, see ambientlight's answer.

Sign up to request clarification or add additional context in comments.

2 Comments

@HansBrende: NSData still has a getBytes method in Swift 3, only its overlay type Data hasn't. I have added a Data version, another solution for Swift 3 was already posted by ambientlight.
@HansBrende: See also stackoverflow.com/questions/38023838/… for a more general treatment of conversion to Data and back.
17

In Swift 3 it is now a bit more wordy:

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)

1 Comment

How is this performance wise? Any overhead in terms of data-copying and allocations / retain cycles? I want to replace NSMutableData in my server-swift code with [UInt8]
14

I think Martin's answer is better than this, but I still want to post mine. Any suggestion would be really helpful.

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

3 Comments

Than why not to accept Martin's answer? There is a tick button under the number of "upvotes". Its a tick, when you click on it, it becomes green.
Actually, your answer was very helpful for me. I was getting wrong int values with the accepted method, but yours gave me the correct result. I was probably just implementing the accepted method wrong but still...
This failed for signed number. How to modify this for Signed integer? Ex: [0xFF,0xFF,0xFF,0xAB]
11

The problem with the accepted answer comes when you don't know the size of your bytes array (or your Data size)

It works well with let array : [UInt8] = [0, 0, 0x23, 0xFF]

But it won't work with let array : [UInt8] = [0x23, 0xFF]
(because it will be considered as [0x23, 0xFF, 0, 0])

That's why I like the @Jerry's one, with bitwise operation.

I've made a functional version of his code snippet.

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

1 Comment

This should be the accepted answer
6

Updated for Swift 5, two things to pay attention:

  • As [UInt8] is stored in a contiguous region of memory, there's no need to convert it to Data, pointer can access all bytes directly.

  • Int's byte order is little endian currently on all Apple platform, but this is not garanteed on other platforms.

say we want [0, 0, 0, 0x0e] to convert to 14. (big-endian byte order)

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

Comments

1

For those who prefer to do it the old-fashioned way, here's a set of methods for getting int values from a byte array. This is intended for situations where a byte array containing various kinds of data is being processed sequentially.

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

This is an extract from a larger class that includes methods for extracting strings and other kinds of data. See also here: https://stackoverflow.com/a/41592206/253938

1 Comment

I did try to use this class but I am facing a swift compiler error while running on the Xcode 13 in the function public func getUInt64() -> UInt64 The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.