I'm working with a C API from Swift and for one of the methods that I need to call I need to give a
UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
More Info:
Swift Interface:
public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t
Original C:
presage_error_code_t presage_predict(presage_t prsg, char*** result);
There may be a better way but this runs in playground and defines a value r
with the type you want:
func ptrFromAddress<T>(p:UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
{
return p
}
var myInt:Int8 = 0
var p = ptrFromAddress(&myInt)
var q = ptrFromAddress(&p)
var r = ptrFromAddress(&q)
What's the point of defining ptrFromAddress
, which seems like it does nothing? My thinking is that the section of the Swift interop book which discusses mutable pointers shows many ways to initialize them by passing some expression as an argument (like &x
), but does not seem to show corresponding ways where you simply call UnsafeMutablePointer
's initializer. So let's define a no-op function just to use those special initialization methods based on argument-passing
While I believe the method above is correct, it was pointed out by @alisoftware in another forum that this seems to be a safer and more idiomatic way to do the same thing:
var myInt: Int8 = 0
withUnsafeMutablePointer(&myInt) { (var p) in
withUnsafeMutablePointer(&p) { (var pp) in
withUnsafeMutablePointer(&pp) { (var ppp) in
// Do stuff with ppp which is a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
}
}
}
It's more idiomatic because you're using the function withUnsafeMutablePointer
which is supplied by the Swift standard library, rather than defining your own helper. It's safer because you are guaranteed that the UnsafeMutablePointer
is only alive during the extent of the call to the closure (so long as the closure itself does not store the pointer).
Generally, if a function takes a UnsafePointer<T>
parameter
then you can pass a variable of type T
as in "inout" parameter with &
. In your case, T
is
UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
which is the Swift mapping of char **
. So you can call the C function
as
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
From the documentation and sample code of the Presage library I
understand that this allocates an array of strings and assigns the
address of this array to the variable pointed to by prediction
.
To avoid a memory leak, these strings have to be released eventually
with
presage_free_string_array(prediction)
To demonstrate that this actually works, I have taken the first part of the demo code at presage_c_demo.c and translated it to Swift:
// Duplicate the C strings to avoid premature deallocation:
let past = strdup("did you not sa")
let future = strdup("")
func get_past_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(past)
}
func get_future_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(future)
}
var prsg = presage_t()
presage_new(get_past_stream, nil, get_future_stream, nil, &prsg)
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK {
for var i = 0; prediction[i] != nil; i++ {
// Convert C string to Swift `String`:
let pred = String.fromCString(prediction[i])!
print ("prediction[\(i)]: \(pred)")
}
presage_free_string_array(prediction)
}
free(past)
free(future)
This actually worked and produced the output
prediction[0]: say prediction[1]: said prediction[2]: savages prediction[3]: saw prediction[4]: sat prediction[5]: same
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With