Convert bytes/UInt8 array to Int in Swift

51,623

Solution 1

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.

Solution 2

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)

Solution 3

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

Solution 4

There's some good answers here, which is really nice to see ^^ However if you'd like to avoid interacting with the C-interopability API of Swift, then I recommend to take a look at my example. It's also just as generic for all the datatype sizes. Note that MemoryLayout is only being used a sanity check.

Code:

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

Example usage:

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

For little endian support, you need for byte in bytes.reversed() instead.

Explanation:

<<= is the bitwise left shift assignment operator: It shifts the left hand operand (usually a numerical value type) by N bits defined by the right hand operand, for example:

0b00000001 << 7 == 0b10000000

|= is the bitwise or assignment operator: It applies a bitwise or on the left and right hand operands, for example:

0b00000001 | 0b10000000 == 0b10000001

So when you have an array of 2 unsinged bytes and want to convert it a unsinged short you can simply;

let bytes = [UInt8](repeating: UInt8(255), count: 2)
var short: UInt16 = 0

// "add" our first unsinged byte
short |= UInt16(bytes[0])
// our short now looks like this in memory: 0b0000000011111111

// make room for the unsinged byte ;)
short <<= 8 
// our short now looks like this in memory: 0b1111111100000000

// "add" our last unsinged byte
short |= UInt16(bytes[1])
// our short now looks like this in memory: 0b1111111111111111

print(short == UInt16.max)

Solution 5

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)
}
Share:
51,623
Jerry
Author by

Jerry

Updated on January 13, 2020

Comments

  • Jerry
    Jerry over 4 years

    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