29

How does one access bytes (or Int16's, floats, etc.) out of memory pointed to by an UnsafeMutableRawPointer (new in Swift 3) handed to a Swift function by a C API (Core Audio, etc.)

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • 1
    Can you please give us a [minimal, complete, and verifiable example](http://stackoverflow.com/help/mcve) of some concrete data to work with? – Alexander Aug 16 '16 at 19:49
  • 3
    The [Swift Evolution proposal for `UnsafeRawPointer`](https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md) may be a good place to start – gives a good overview on the API with examples. – Hamish Aug 16 '16 at 19:54

4 Answers4

50

load<T> reads raw bytes from memory and constructs a value of type T:

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

optionally at a byte offset:

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

There is also assumingMemoryBound() which converts from a Unsafe[Mutable]RawPointer to a Unsafe[Mutable]Pointer<T>, assuming that the pointed-to memory contains a value of type T:

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

For an array of values you can create a "buffer pointer":

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

A buffer pointer might already be sufficient for your purpose, it is subscriptable and can be enumerated similarly to an array. If necessary, create an array from the buffer pointer:

let i16array = Array(i16bufptr)

As @Hamish said, more information and details can be found at

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thanks! That works for the 1st element. How about for UInt16's (plural), as there could be an array of data? (in an Int16 audio sample buffer, for example) – hotpaw2 Aug 16 '16 at 20:16
  • ptr.assumingMemoryBound(to: Int16.self).pointee = Int16(foo()) ; ptr += 2 // also seems to work for assigning to array elements sequentially – hotpaw2 Aug 16 '16 at 21:31
  • @hotpaw2: Yes, and that works also with `load`. The buffer pointer method is useful to assign an array of value in one step. Isn't that what you asked for? – Martin R Aug 16 '16 at 21:45
  • How do you assign let ptr = ... // Unsafe[Mutable]RawPointer in swift-3 . – Shrawan Dec 20 '16 at 13:04
  • when filling the buffer I get `Cannot assign through subscript, subscript is get only` error – Necktwi May 19 '17 at 16:10
  • `i16bufptr[0]=32` – Necktwi May 19 '17 at 16:56
  • @neckTwi: This question is about *reading* the bytes referenced by a raw pointer. If you want to mutate it then you need `let i16bufptr = UnsafeMutableBufferPointer(...)` – Martin R May 19 '17 at 17:01
  • @MartinR please help here https://stackoverflow.com/questions/57195022/what-is-replacement-of-cfreadstreamcreateforstreamedhttprequest – Amit Jul 25 '19 at 05:57
4

Here's a Swift 4 example of converting a literal UInt8 array to an UnsafeMutableRawPointer and back to an UInt32 array

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)
}
Mike Lee
  • 2,440
  • 26
  • 12
3

Create Data object.

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

One important way missing from the other answers here is initialising a Data object with UnsafeMutableRawPointer. The data object can then be used for other calculations.

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
}
Sverrisson
  • 17,970
  • 5
  • 66
  • 62
2

Here are the api documentation of Unsafe[Mutable]RawPointer to T/Unsafe[MutablePointer] conversion:

/// 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

and then from Unsafe[MutablePointer]<T> toT can be converted with pointee and move apis

/// 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
Ankit Thakur
  • 4,739
  • 1
  • 19
  • 35