将 bytes/UInt8 数组转换为 Swift 中的 Int
Convert bytes/UInt8 array to Int in Swift
如何将一个4字节数组转换成对应的Int?
let array: [UInt8] ==> let value : Int
示例:
输入:
[=13=][=13=][=13=]\x0e
输出:
14
我在 Internet 上找到的一些代码不起作用:
let data = NSData(bytes: array, length: 4)
data.getBytes(&size, length: 4)
// the output to size is 184549376
有两个问题:
Int
是64位平台上的64位整数,你的输入数据
只有 32 位。
Int
在所有当前 Swift 平台上使用小端表示,
你的输入是大端。
话虽这么说,但以下方法可行:
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
或在 Swift 中使用 Data
3:
let array : [UInt8] = [0, 0, 0, 0x0E]
let data = Data(bytes: array)
let value = UInt32(bigEndian: data.withUnsafeBytes { [=11=].pointee })
使用一些缓冲区指针魔法,您可以避免中间过程
复制到 NSData
对象 (Swift 2):
let array : [UInt8] = [0, 0, 0, 0x0E]
var value = array.withUnsafeBufferPointer({
UnsafePointer<UInt32>([=12=].baseAddress).memory
})
value = UInt32(bigEndian: value)
print(value) // 14
对于此方法的 Swift 3 版本,请参阅 ambientlight 的回答。
我认为 Martin 的回答比这更好,但我仍然想 post 我的。任何建议都会很有帮助。
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
在Swift 3中现在有点罗嗦了:
let array : [UInt8] = [0, 0, 0, 0x0E]
let bigEndianValue = array.withUnsafeBufferPointer {
([=10=].baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1) { [=10=] })
}.pointee
let value = UInt32(bigEndian: bigEndianValue)
对于那些喜欢用老式方法来做的人,这里有一组从字节数组中获取 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
}
}
这是从更大的 class 中摘录的,其中包括用于提取字符串和其他类型数据的方法。另见此处:
这里有一些很好的答案,真的很高兴看到^^
但是,如果您想避免与 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)
}
}
用法示例:
let someBytes = [UInt8](repeating: 0x42, count: 2)
let someValue = UInt16(someBytes)
对于小端支持,您需要 for byte in bytes.reversed()
。
解释:
<<= 是按位左移赋值运算符:
它将左手操作数(通常是数值类型)移动右手操作数定义的 N 位,例如:
0b00000001 << 7 == 0b10000000
|= 是按位或赋值运算符:
它对左右操作数应用按位或,例如:
0b00000001 | 0b10000000 == 0b10000001
因此,当您有一个包含 2 个未签名字节的数组并想将其转换为未签名的短整型时,您可以简单地;
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)
当您不知道字节数组的大小时(或您的 Data
大小)
它适用于 let array : [UInt8] = [0, 0, 0x23, 0xFF]
但它不适用于 let array : [UInt8] = [0x23, 0xFF]
(因为会被认为是[0x23, 0xFF, 0, 0]
)
这就是为什么我喜欢@Jerry 的按位运算的原因。
我已经制作了他的代码片段的功能版本。
let data = Data(bytes: [0x23, 0xFF])
let decimalValue = data.reduce(0) { v, byte in
return v << 8 | Int(byte)
}
更新为Swift5,注意两点:
由于[UInt8]
存储在连续的内存区域,因此无需将其转换为Data
,指针可以直接访问所有字节。
Int
的字节顺序目前在所有Apple平台上都是小端,但在其他平台上不保证。
假设我们希望 [0, 0, 0, 0x0e]
转换为 14
。 (big-endian 字节顺序)
let source: [UInt8] = [0, 0, 0, 0x0e]
let bigEndianUInt32 = source.withUnsafeBytes { [=10=].load(as: UInt32.self) }
let value = CFByteOrderGetCurrent() == CFByteOrder(CFByteOrderLittleEndian.rawValue)
? UInt32(bigEndian: bigEndianUInt32)
: bigEndianUInt32
print(value) // 14
如何将一个4字节数组转换成对应的Int?
let array: [UInt8] ==> let value : Int
示例:
输入:
[=13=][=13=][=13=]\x0e
输出:
14
我在 Internet 上找到的一些代码不起作用:
let data = NSData(bytes: array, length: 4)
data.getBytes(&size, length: 4)
// the output to size is 184549376
有两个问题:
Int
是64位平台上的64位整数,你的输入数据 只有 32 位。Int
在所有当前 Swift 平台上使用小端表示, 你的输入是大端。
话虽这么说,但以下方法可行:
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
或在 Swift 中使用 Data
3:
let array : [UInt8] = [0, 0, 0, 0x0E]
let data = Data(bytes: array)
let value = UInt32(bigEndian: data.withUnsafeBytes { [=11=].pointee })
使用一些缓冲区指针魔法,您可以避免中间过程
复制到 NSData
对象 (Swift 2):
let array : [UInt8] = [0, 0, 0, 0x0E]
var value = array.withUnsafeBufferPointer({
UnsafePointer<UInt32>([=12=].baseAddress).memory
})
value = UInt32(bigEndian: value)
print(value) // 14
对于此方法的 Swift 3 版本,请参阅 ambientlight 的回答。
我认为 Martin 的回答比这更好,但我仍然想 post 我的。任何建议都会很有帮助。
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
在Swift 3中现在有点罗嗦了:
let array : [UInt8] = [0, 0, 0, 0x0E]
let bigEndianValue = array.withUnsafeBufferPointer {
([=10=].baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1) { [=10=] })
}.pointee
let value = UInt32(bigEndian: bigEndianValue)
对于那些喜欢用老式方法来做的人,这里有一组从字节数组中获取 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
}
}
这是从更大的 class 中摘录的,其中包括用于提取字符串和其他类型数据的方法。另见此处:
这里有一些很好的答案,真的很高兴看到^^ 但是,如果您想避免与 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)
}
}
用法示例:
let someBytes = [UInt8](repeating: 0x42, count: 2)
let someValue = UInt16(someBytes)
对于小端支持,您需要 for byte in bytes.reversed()
。
解释:
<<= 是按位左移赋值运算符: 它将左手操作数(通常是数值类型)移动右手操作数定义的 N 位,例如:
0b00000001 << 7 == 0b10000000
|= 是按位或赋值运算符: 它对左右操作数应用按位或,例如:
0b00000001 | 0b10000000 == 0b10000001
因此,当您有一个包含 2 个未签名字节的数组并想将其转换为未签名的短整型时,您可以简单地;
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)
当您不知道字节数组的大小时(或您的 Data
大小)
它适用于 let array : [UInt8] = [0, 0, 0x23, 0xFF]
但它不适用于 let array : [UInt8] = [0x23, 0xFF]
(因为会被认为是[0x23, 0xFF, 0, 0]
)
这就是为什么我喜欢@Jerry 的按位运算的原因。
我已经制作了他的代码片段的功能版本。
let data = Data(bytes: [0x23, 0xFF])
let decimalValue = data.reduce(0) { v, byte in
return v << 8 | Int(byte)
}
更新为Swift5,注意两点:
由于
[UInt8]
存储在连续的内存区域,因此无需将其转换为Data
,指针可以直接访问所有字节。Int
的字节顺序目前在所有Apple平台上都是小端,但在其他平台上不保证。
假设我们希望 [0, 0, 0, 0x0e]
转换为 14
。 (big-endian 字节顺序)
let source: [UInt8] = [0, 0, 0, 0x0e]
let bigEndianUInt32 = source.withUnsafeBytes { [=10=].load(as: UInt32.self) }
let value = CFByteOrderGetCurrent() == CFByteOrder(CFByteOrderLittleEndian.rawValue)
? UInt32(bigEndian: bigEndianUInt32)
: bigEndianUInt32
print(value) // 14