【问题标题】:How to get bytes out of an UnsafeMutableRawPointer?如何从 UnsafeMutableRawPointer 中获取字节?
【发布时间】:2023-03-19 13:05:02
【问题描述】:

如何访问由 C API(Core Audio 等)传递给 Swift 函数的 UnsafeMutableRawPointer(Swift 3 中的新功能)指向的内存中的字节(或 Int16、浮点数等)

【问题讨论】:

标签: swift unsafe-pointers


【解决方案1】:

这是一个将文字 UInt8 数组转换为 UnsafeMutableRawPointer 并返回到 UInt32 数组的 Swift 4 示例

static func unsafePointerTest() {
    //let a : [UInt8] = [0,0,0,4,0,0,0,8,0,0,0,12]
    let a : [UInt8] = [0x04, 0x00, 0x00, 0x00,
                       0x08, 0x00, 0x00, 0x00,
                       0x0C, 0x00, 0x00, 0x00] //little endian
    //0xFF, 0xF0, 0xF0, 0x12]  //317780223 = 12F0F0FF
    let b:UnsafeMutableRawPointer = UnsafeMutableRawPointer(mutating:a)
    let bTypedPtr = b.bindMemory(to: UInt32.self, capacity: a.count/4)
    let UInt32Buffer = UnsafeBufferPointer(start: bTypedPtr, count: a.count/4)
    let output = Array(UInt32Buffer)
    print(output)
}

【讨论】:

    【解决方案2】:

    创建数据对象。

    init(bytesNoCopy bytes: UnsafeMutableRawPointer, count: Int, deallocator: Data.Deallocator)
    

    这里的其他答案中缺少的一个重要方法是使用 UnsafeMutableRawPointer 初始化 Data 对象。然后可以将数据对象用于其他计算。

    public func base64(quality: Int32 = 67) -> String? {
        var size: Int32 = 0
        if let image = gdImageJpegPtr(internalImage, &size, quality) {
            // gdImageJpegPtr returns an UnsafeMutableRawPointer that is converted to a Data object
            let d = Data(bytesNoCopy: image, count: Int(size), deallocator: .none)
            return d.base64EncodedString()
        }
        return nil
    }
    

    【讨论】:

    • 这非常方便!我需要将 dealloc 更改为 none,但这对我有用。非常感谢。
    【解决方案3】:

    这里是 Unsafe[Mutable]RawPointer 到 T/Unsafe[MutablePointer] 转换的 api 文档:

    /// Binds the allocated memory to type `T` and returns an
    /// `UnsafePointer<T>` to the bound memory at `self`.
    ///
    /// - Precondition: The memory is uninitialized.
    /// - Postcondition: The memory is bound to 'T' starting at `self` continuing
    ///   through `self` + `count` * `MemoryLayout<T>.stride`
    /// - Warning: Binding memory to a type is potentially undefined if the
    ///   memory is ever accessed as an unrelated type.
    public func bindMemory<T>(to type: T.Type, capacity count: Int) -> UnsafePointer<T>
    
    /// Converts from an `UnsafeRawPointer` to UnsafePointer<T> given that
    /// the region of memory starting at `self` is already bound to type `T`.
    ///
    /// - Precondition: The memory is bound to 'T' starting at `self` for some
    ///   unspecified capacity.
    ///
    /// - Warning: Accessing memory via the returned pointer is undefined if the
    ///   if the memory has not been bound to `T`.
    public func assumingMemoryBound<T>(to: T.Type) -> UnsafePointer<T>
    
    /// Reads raw bytes from memory at `self + offset` and constructs a
    /// value of type `T`.
    ///
    /// - Precondition: The underlying pointer plus `offset` is properly
    ///   aligned for accessing `T`.
    ///
    /// - Precondition: The memory is initialized to a value of some type, `U`,
    ///   such that `T` is layout compatible with `U`.
    public func load<T>(fromByteOffset offset: Int = default, as type: T.Type) -> T
    

    然后从Unsafe[MutablePointer]&lt;T&gt;T 可以转换为 pointeemove api

    /// Accesses the `Pointee` instance referenced by `self`.
    ///
    /// - Precondition: the pointee has been initialized with an instance of
    ///   type `Pointee`.
    public var pointee: Pointee { get }
    
    /// Retrieves the `pointee`, returning the referenced memory to an
    /// uninitialized state.
    ///
    /// Equivalent to `{ defer { deinitialize() }; return pointee }()`, but
    /// more efficient.
    ///
    /// - Precondition: The pointee is initialized.
    ///
    /// - Postcondition: The memory is uninitialized.
    public func move() -> Pointee
    

    【讨论】:

      【解决方案4】:

      load&lt;T&gt; 从内存中读取原始字节并构造一个T 类型的值:

      let ptr = ... // Unsafe[Mutable]RawPointer
      let i16 = ptr.load(as: UInt16.self)
      

      可选地在字节偏移处:

      let i16 = ptr.load(fromByteOffset: 4, as: UInt16.self)
      

      还有assumingMemoryBound(),它从Unsafe[Mutable]RawPointer转换为Unsafe[Mutable]Pointer&lt;T&gt;,假设指向的内存包含一个类型为T的值:

      let i16 = ptr.assumingMemoryBound(to: UInt16.self).pointee
      

      对于值数组,您可以创建一个“缓冲区指针”:

      let i16bufptr = UnsafeBufferPointer(start: ptr.assumingMemoryBound(to: UInt16.self), count: count)
      

      缓冲区指针可能已经足以满足您的目的,它 是可下标的,并且可以像数组一样枚举。 如有必要,从缓冲区指针创建一个数组:

      let i16array = Array(i16bufptr)
      

      正如@Hamish 所说,更多信息和细节可以在

      找到

      【讨论】:

      • 谢谢!这适用于第一个元素。 UInt16(复数)怎么样,因为可能有一组数据? (例如在 Int16 音频样本缓冲区中)
      • ptr.sumptionMemoryBound(to: Int16.self).pointee = Int16(foo()) ; ptr += 2 // 似乎也适用于按顺序分配给数组元素
      • @hotpaw2:是的,这也适用于load。缓冲区指针方法对于一次性分配值数组很有用。这不是你要求的吗?
      • 你如何分配 let ptr = ... // Unsafe[Mutable]RawPointer in swift-3 .
      • 填充缓冲区时出现Cannot assign through subscript, subscript is get only 错误
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      • 2012-04-02
      • 2014-07-25
      • 1970-01-01
      相关资源
      最近更新 更多