如何创建一个 UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

How to create a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

我正在使用来自 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 处的部分演示代码并进行了翻译 到 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)

这确实有效并产生了输出

prediction[0]: say
prediction[1]: said
prediction[2]: savages
prediction[3]: saw
prediction[4]: sat
prediction[5]: same

可能有更好的方法,但这在 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 interop 书的部分显示了许多通过将一些表达式作为参数传递来初始化它们的方法(如 &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,而不是定义您自己的助手。它更安全,因为可以保证 UnsafeMutablePointer 仅在调用闭包期间有效(只要闭包本身不存储指针)。