代码之家  ›  专栏  ›  技术社区  ›  Nykholas

如何创建UnsafeMutablePointer<UnsafeMatablePointer>

  •  12
  • Nykholas  · 技术社区  · 9 年前

    我正在使用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);
    
    2 回复  |  直到 9 年前
        1
  •  17
  •   Martin R    9 年前

    通常,如果函数采用 UnsafePointer<T> 参数 然后可以传递类型为 T 如“inout”参数中所示 & 在您的情况下, T

    UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
    

    这是Swift映射 char ** 。因此您可以调用C函数 像

    var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
    if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
    

    来自Presage库I的文档和示例代码 了解这将分配字符串数组,并将 此数组指向的变量的地址 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
    
        2
  •  5
  •   algal    9 年前

    也许有更好的方法,但这在操场上运行并定义了一个值 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 的初始值设定项。因此,让我们定义一个no op函数,以使用基于参数传递的特殊初始化方法

    更新:

    虽然我相信上面的方法是正确的,但@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>>>
        }
      }
    }
    

    它更地道,因为您使用的是函数 withUnsafeMutablePointer 它由Swift标准库提供,而不是定义自己的助手。这样更安全,因为你保证 不安全可变指针 仅在调用闭包的范围内有效(只要闭包本身不存储指针)。