如何将一个Swiftstring数组传递给一个带有char **参数的C函数
我正试图与Swift的一个旧的Cterminal应用进行交互。 我已经成功地集成了源代码,并将C的头文件桥接到了Swift中。 代码编译并从Xcode 6.3 beta运行。 我已经将terminal应用的主要入口重命名为:
int initialize(int argc, char **argv);
不过,我正在努力将Swift的parameter passing给这个C函数。 我的挑战是以正确的格式转换参数。 Swift的典型input如下所示:
let args = ["-c", "1.2.3.4", "-p", "8000"]
我试图搞乱“cStringUsingEncoding(NSUTF8StringEncoding)”和“withUnsafePointer”,但没有运气到目前为止。 任何帮助是极大的赞赏!
C函数
int initialize(int argc, char **argv);
被映射为Swift
func initialize(argc: Int32, argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>) -> Int32
这是一个可能的解决scheme:
let args = ["-c", "1.2.3.4", "-p", "8000"] // Create [UnsafeMutablePointer<Int8>]: var cargs = args.map { strdup($0) } // Call C function: let result = initialize(Int32(args.count), &cargs) // Free the duplicated strings: for ptr in cargs { free(ptr) }
它使用的事实是,在strdup($0)
,Swiftstring$0
会自动转换为一个Cstring,正如在String value到UnsafePointer <UInt8>函数参数行为中所述 。
build立在Martin的答案上,如果你发现自己做了这么多事情,你可以用与String.withCString
类似的风格将dup / free部分包装成一个函数:
import Darwin func withCStrings <R, S: SequenceType where S.Generator.Element == String> (strings: S, @noescape body: (UnsafeBufferPointer<UnsafeMutablePointer<Int8>>) -> R) -> R { let cstrings = map(strings) { strdup($0) } + [nil] let result = cstrings.withUnsafeBufferPointer(body) for ptr in cstrings { free(ptr) } return result } let execvargs = ["/usr/bin/say"] + dropFirst(Process.arguments) let execvresult = withCStrings(execvargs) { execv($0[0], $0.baseAddress) }