我正在从Swift 4调用一个C库,我遇到了将[String]
转换为const char *[]
的麻烦。
C API定义了这个方法:
int getDREFs(const char* drefs[], unsigned char count);
在Swift中曝光的
public func getDREFs(_ drefs: UnsafeMutablePointer<UnsafePointer<Int8>?>!, _ count: UInt8) -> Int32
我正在尝试编写的Swift包装器如下
public func get(drefs: [String]) throws {
var cDrefs = [UnsafePointer<Int8>]()
for dref in drefs {
cDrefs.append(dref.cString(using: .utf8)!)
}
let pDrefs = UnsafeMutablePointer<UnsafePointer<Int8>>(&cDrefs)
getDREFFs(pDrefs, drefs.count)
}
但我得到的错误是
Cannot convert value of type 'UnsafeMutablePointer<UnsafePointer<Int8>>' to expected argument type 'UnsafeMutablePointer<UnsafePointer<Int8>?>!'
我错过了什么?
getDREFSs
期望一个指向可选Int8
指针数组的指针。第二个参数也必须转换为UInt8
。
所以这将编译:
public func get(drefs: [String]) -> Int {
var cDrefs = [UnsafePointer<Int8>?]()
for dref in drefs {
cDrefs.append(dref.cString(using: .utf8))
}
let result = getDREFs(&cDrefs, UInt8(drefs.count))
return Int(result)
}
但是快速测试显示,如果使用多个字符串调用则不起作用。原因是当调用C函数时,dref.cString(using: .utf8)
返回的数组已经被释放(并且指针无效)。
这是一个工作版本,对这个特殊情况略有修改Convert a Swift Array of String to a to a C string array pointer:
public func get(drefs: [String]) -> Int {
var cargs = drefs.map { UnsafePointer<Int8>(strdup($0)) }
let result = getDREFs(&cargs, UInt8(drefs.count))
for ptr in cargs { free(UnsafeMutablePointer(mutating: ptr)) }
return Int(result)
}