如何使用char **参数将Swift字符串数组传递给C函数

时间:2015-04-06 10:09:33

标签: c swift language-interoperability

我正在尝试与Swift的旧C终端应用程序进行交互。我已成功集成源代码并将标头从C桥接到Swift。该代码从Xcode 6.3 beta编译并运行。我已将终端应用程序的主要入口点重命名为:

int initialize(int argc, char **argv);

然而,我正在努力将Swift中的参数传递给这个C函数。我的挑战是以正确的格式转换参数。 Swift的典型输入看起来像:

let args = ["-c", "1.2.3.4", "-p", "8000"]

我已经尝试过使用“cStringUsingEncoding(NSUTF8StringEncoding)”和“withUnsafePointer”,但到目前为止还没有运气。非常感谢任何帮助!

2 个答案:

答案 0 :(得分:9)

C函数

int initialize(int argc, char **argv);

映射到Swift为

func initialize(argc: Int32, argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>) -> Int32

这是一个可能的解决方案:

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)中的事实 Swift字符串$0自动转换为C字符串, 正如String value to UnsafePointer<UInt8> function parameter behavior中所述。

答案 1 :(得分:0)

根据Martin的回答,如果你发现自己做了很多,你可以将dup / free部分包装成一个与String.withCString类似的函数:

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)
}