我正在使用Swift的C API,对于我需要调用的方法之一,我需要给出一个
UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
更多信息:
Swift接口:
public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t
原C:
presage_error_code_t presage_predict(presage_t prsg, char*** result);
一般情况下,如果函数接受UnsafePointer<T>
参数然后,您可以传递T
类型的变量,如&
的"inout"参数。在您的示例中,T
是
UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
是char **
的Swift映射。你可以调用C函数
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
来自Presage库的文档和示例代码要理解,这将分配一个字符串数组,并将prediction
所指向的变量的地址。为了避免内存泄漏,必须最终释放这些字符串
presage_free_string_array(prediction)
为了证明这实际上是有效的,我选择了第一个在presage_c_demo.c下载部分演示代码并翻译斯威夫特:
// 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)
这实际上有效并产生了输出
<>之前预测[0]:说预测[1]:说预测[2]:野蛮人预测[3]:看到了预测[4]:坐预测[5]:相同可能有更好的方法,但这在playground中运行,并定义了一个值r
与您想要的类型:
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)
定义ptrFromAddress
有什么意义,它似乎什么都不做?我的想法是Swift互操作书中讨论可变指针的部分展示了许多通过传递一些表达式作为参数(如&x
)来初始化它们的方法,但似乎没有显示相应的方法,您只需调用UnsafeMutablePointer
的初始化器。那么让我们定义一个无操作函数来使用那些基于参数传递的特殊初始化方法
更新:
虽然我相信上面的方法是正确的,但另一个论坛上的@alisoftware指出,这似乎是一种更安全、更习惯的方法来做同样的事情:
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>>>
}
}
}
它更习惯,因为你使用的是Swift标准库提供的withUnsafeMutablePointer
函数,而不是定义你自己的helper。它更安全,因为您可以保证UnsafeMutablePointer
仅在调用闭包的范围内是活动的(只要闭包本身不存储指针)。