简体   繁体   English

如何创建UnsafeMutablePointer <UnsafeMutablePointer<UnsafeMutablePointer<Int8> &gt;&gt;

[英]How to create a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

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 我正在使用Swift的C API,并且我需要调用一个方法,我需要给出一个

UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

More Info: 更多信息:

Swift Interface: Swift接口:

public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t

Original C: 原C:

presage_error_code_t presage_predict(presage_t prsg, char*** result);

Generally, if a function takes a UnsafePointer<T> parameter then you can pass a variable of type T as in "inout" parameter with & . 一般而言,如果用函数采用一个UnsafePointer<T>参数然后可以传递类型的变量T如结合“INOUT”参数& In your case, T is 在你的情况下, T

UnsafeMutablePointer<UnsafeMutablePointer<Int8>>

which is the Swift mapping of char ** . 这是char **的Swift映射。 So you can call the C function as 所以你可以调用C函数

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 . 从Presage库的文档和示例代码中我了解到,这会分配一个字符串数组,并将此数组的地址分配给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: 为了证明这实际上有效,我在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)

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

There may be a better way but this runs in playground and defines a value r with the type you want: 可能有更好的方法,但这在游乐场中运行,并使用您想要的类型定义值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)

What's the point of defining ptrFromAddress , which seems like it does nothing? 定义ptrFromAddress什么ptrFromAddress ,好像什么都没做? 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. 我的想法是,Swift interop书中讨论可变指针的部分显示了许多通过将一些表达式作为参数(如&x )传递来初始化它们的方法,但似乎没有显示相应的方法,只需调用UnsafeMutablePointer的初始化程序。 So let's define a no-op function just to use those special initialization methods based on argument-passing 因此,让我们定义一个无操作函数,只是为了使用基于参数传递的特殊初始化方法

Update: 更新:

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

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. 它更加惯用,因为你正在使用由Swift标准库提供的函数withUnsafeMutablePointer ,而不是定义你自己的帮助器。 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). 它更安全,因为您可以保证UnsafeMutablePointer仅在对闭包的调用范围UnsafeMutablePointer活(只要闭包本身不存储指针)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM