将 4 字节 (Swift3) 数据获取到 UInt32 的两种方法

问题描述 投票:0回答:4

因此,我有来自某些硬件的格式良好的数据流。该流由一堆 8 位数据块组成,其中一些数据旨在形成 32 位整数。这一切都很好。数据继续移动,现在我想将序列打包。

数据实际上是一个连续的字节块,其中的各个部分映射到有用的数据。因此,例如,第一个字节是确认码,接下来的四个字节表示具有某种特定于应用程序含义的 UInt32,后面是表示 UInt16 的两个字节,依此类推,有几十个字节。

我发现了两种不同的方法来做到这一点,这两种方法似乎都有点……过度紧张。当你靠近金属时,可能就会发生这种情况。

但是——这两种代码习惯通常是人们应该期望做的事情吗?或者我错过了一些更紧凑的东西?

  // data : Data exists before this code, and has what we're transforming into UInt32

  // One Way to get 4  bytes from Data into a UInt32
  var y : [UInt8] = [UInt8](repeating:UInt8(0x0), count: 4)
  data.copyBytes(to: &y, from: Range(uncheckedBounds: (2,6)))
  let u32result = UnsafePointer(y).withMemoryRebound(to: UInt32.self, capacity: 1, {
       $0.pointee
  })
  // u32result contains the 4 bytes from data

  // Another Way to get 4 bytes from Data into a UInt32 via NSData
  var result : UInt32 = 0
  let resultAsNSData : NSData = data.subdata(in: Range(uncheckedBounds: (2,6))) as NSData
  resultAsNSData.getBytes(&result, range: NSRange(location: 0, length: 4))
  // result contains the 4 bytes from data
swift swift3 nsdata
4个回答
2
投票

从格式正确的数据对象创建 UInt32 数组。

斯威夫特3

// Create sample data
let data = "foo".data(using: .utf8)!

// Using pointers style constructor
let array = data.withUnsafeBytes {
    [UInt32](UnsafeBufferPointer(start: $0, count: data.count))
}
    

斯威夫特2

// Create sample data
let data = "foo".dataUsingEncoding(NSUTF8StringEncoding)!
        
// Using pointers style constructor
let array = Array(UnsafeBufferPointer(start: UnsafePointer<UInt32>(data.bytes), count: data.length))

2
投票

我发现了另外两种方法可以做到这一点,这让我相信有很多方法可以做到这一点,我想这很好。 Ray Wenderlich

以某种方式描述了另外两种方法

将此代码放入您的 Xcode 游乐场中将揭示这两个其他习惯用法。

do {
let count = 1 // number of UInt32s
let stride = MemoryLayout<UInt32>.stride
let alignment = MemoryLayout<UInt32>.alignment
let byteCount = count * stride

var bytes : [UInt8] = [0x0D, 0x0C, 0x0B, 0x0A] // little-endian LSB -> MSB
var data : Data = Data.init(bytes: bytes) // In my situtation, I actually start with an instance of Data, so the [UInt8] above is a conceit.

print("---------------- 1 ------------------")

let placeholder = UnsafeMutableRawPointer.allocate(bytes: byteCount, alignedTo:alignment)

withUnsafeBytes(of: &data, { (bytes) in
    for (index, byte) in data.enumerated() {
        print("byte[\(index)]->\(String(format: "0x%02x",byte)) data[\(index)]->\(String(format: "0x%02x", data[index])) addr: \(bytes.baseAddress!+index)")

        placeholder.storeBytes(of: byte, toByteOffset: index, as: UInt8.self)

    }
})
let typedPointer1 = placeholder.bindMemory(to: UInt32.self, capacity: count)
print("u32: \(String(format: "0x%08x", typedPointer1.pointee))")



print("---------------- 2 ------------------")

for (index, byte) in bytes.enumerated() {
    placeholder.storeBytes(of: byte, toByteOffset: index, as: UInt8.self)
   // print("byte \(index): \(byte)")
    print("byte[\(index)]->\(String(format: "0x%02x",byte))")

}
let typedPointer = placeholder.bindMemory(to: UInt32.self, capacity: count)
print(typedPointer.pointee)
let result : UInt32 = typedPointer.pointee
print("u32: \(String(format: "0x%08x", typedPointer.pointee))")
}

有输出:

---------------- 1 ------------------
byte[0]->0x0d data[0]->0x0d addr: 0x00007fff57243f68
byte[1]->0x0c data[1]->0x0c addr: 0x00007fff57243f69
byte[2]->0x0b data[2]->0x0b addr: 0x00007fff57243f6a
byte[3]->0x0a data[3]->0x0a addr: 0x00007fff57243f6b
u32: 0x0a0b0c0d
---------------- 2 ------------------
byte[0]->0x0d
byte[1]->0x0c
byte[2]->0x0b
byte[3]->0x0a
168496141
u32: 0x0a0b0c0d

这是要点


0
投票

这是一个采用 Swift

Data
并支持从 Swift 中读出多种数字数据类型的方法
Data

func read<T: FixedWidthInteger>(data: Data, offset: Int, length tSize: Int) -> T {
    var value: T = 0
    withUnsafeMutableBytes(of: &value, { bytes -> Void in
        data.withUnsafeBytes { rawBytes -> Void in
            memcpy(bytes.baseAddress!, rawBytes.baseAddress!.advanced(by: offset), tSize)
        }
    })
    return value
}

使用数据:让我们将几个不同的 Swift 数字类型添加到缓冲区中

var value1Signed: Int64 = -1234567
var value1Unsigned: UInt64 = 1234567
let value1Size = MemoryLayout<Int64>.size

var value2Signed: Int32 = -12345
var value2Unsigned: UInt32 = 12345
let value2Size = 4

var value3Signed: Int16 = -123
var value3Unsigned: UInt16 = 123
let value3Size = MemoryLayout<Int16>.size

let ptr: UnsafeMutableRawPointer = malloc(value1Size * 2 +
                                          value2Size * 2 +
                                          value3Size * 2)
var offset: Int = 0
memcpy(ptr.advanced(by: offset), &value1Signed, value1Size)
memcpy(ptr + offset + value1Size, &value1Unsigned, value1Size)
offset += value1Size * 2

memcpy(ptr.advanced(by: offset), &value2Signed, value2Size)
memcpy(ptr + offset + value2Size, &value2Unsigned, value2Size)
offset += value2Size * 2

memcpy(ptr.advanced(by: offset), &value3Signed, value3Size)
memcpy(ptr + offset + value3Size, &value3Unsigned, value3Size)
offset += value3Size * 2

将示例缓冲区复制到 Swift

Data
并测试读取方法

let data = Data(bytes: ptr, count: offset)
read(data: data, offset: 0, length: 8) as Int64 // -1234567
read(data: data, offset: 0 + 8, length: 8) as UInt64 // 1234567

read(data: data, offset: 8 + 8, length: 4) as Int32 // -12345
read(data: data, offset: 8 + 8 + 4, length: 4) as UInt32 // 12345

read(data: data, offset: 8 + 8 + 4 + 4, length: 2) as Int16 // -123
read(data: data, offset: 8 + 8 + 4 + 4 + 2, length: 2) as UInt16 // 123

你也可以直接使用

memcpy
方法从内存指针中读取,而不是使用 Swift
Data
,就像这样

var value: Int16 = 0
memcpy(&value, ptr.advanced(by: 8 + 8 + 4 + 4), 2)
print(value)

-1
投票
let a = [ 0x00, 0x00, 0x00, 0x0e ]
let b = a[0] << 24 + a[1] << 16 + a[2] << 8 + a[3]
print(b) // will print 14. 

我应该描述这个操作吗?

© www.soinside.com 2019 - 2024. All rights reserved.