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

Jer*_*rry 23 arrays int byte swift

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

let array: [UInt8] ==> let value : Int
Run Code Online (Sandbox Code Playgroud)

例:

输入:

\0\0\0\x0e
Run Code Online (Sandbox Code Playgroud)

输出:

14
Run Code Online (Sandbox Code Playgroud)

我在互联网上找到的一些代码不起作用:

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

Mar*_*n R 36

有两个问题:

  • 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
Run Code Online (Sandbox Code Playgroud)

或者Data在Swift 3中使用:

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

使用一些缓冲区指针魔术,您可以避免中间复制到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
Run Code Online (Sandbox Code Playgroud)

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


amb*_*ght 14

在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)
Run Code Online (Sandbox Code Playgroud)


Jer*_*rry 8

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

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
Run Code Online (Sandbox Code Playgroud)

  • 为什么不接受马丁的回答呢?"upvotes"数下有一个勾号按钮.它是一个勾号,当你点击它时,它变成绿色. (3认同)

dua*_*uan 7

为 Swift 5 更新,有两点需要注意:

  • 由于[UInt8]存储在连续的内存区域中,因此无需将其转换为Data,指针可以直接访问所有字节。

  • Int目前所有 Apple 平台上的字节顺序都是 little endian,但这在其他平台上是不保证的。

说我们要[0, 0, 0, 0x0e]转换为14. (大端字节序)

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
Run Code Online (Sandbox Code Playgroud)


Mar*_*tin 6

当您不知道字节数组的Data大小(或您的大小)时,接受的答案就会出现问题

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

但它不会与let array : [UInt8] = [0x23, 0xFF]
(因为它会被视为[0x23, 0xFF, 0, 0]

这就是为什么我喜欢@Jerry's 的一个,按位运算。

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

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


小智 5

这里有一些很好的答案,很高兴看到^^但是,如果您想避免与Swift的C互操作性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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

let someBytes = [UInt8](repeating: 0x42, count: 2)
let someValue = UInt16(someBytes)
Run Code Online (Sandbox Code Playgroud)

为了获得很少的字节序支持,您需要for byte in bytes.reversed()