4バイト配列を対応するIntに変換する方法は?
let array: [UInt8] ==> let value : Int
例:
\0\0\0\x0e
14
let data = NSData(bytes: array, length: 4)
data.getBytes(&size, length: 4)
// the output to size is 184549376
2つの問題があります。
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 3:でData
を使用
let array : [UInt8] = [0, 0, 0, 0x0E]
let data = Data(bytes: array)
let value = UInt32(bigEndian: data.withUnsafeBytes { $0.pointee })
バッファポインタマジックを使用すると、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
Swift 3このアプローチのバージョンについては、アンビエントライトの答えをご覧ください。
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)
マーティンの答えはこれよりも良いと思いますが、私はまだ私の投稿をしたいと思います。どんな提案でも本当に役立つでしょう。
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の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()
が必要です。
受け入れられた答えの問題は、バイト配列のサイズ(または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)
}
Swift 5、次の2つの点に注意してください:
[UInt8]
は連続したメモリ領域に格納されるため、Data
に変換する必要はありません。ポインターはすべてのバイトに直接アクセスできます。
Int
のバイト順は、現在すべてのAppleプラットフォームでリトルエンディアンですが、他のプラットフォームでは保証されていません。
[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
昔ながらの方法を好む人のために、バイト配列から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
}
}
これは、文字列やその他の種類のデータを抽出するためのメソッドを含む、より大きなクラスからの抽出です。こちらもご覧ください: https://stackoverflow.com/a/41592206/253938