Как передать массив строк Swift в функцию C, принимающую параметр char **

Я пытаюсь взаимодействовать со старым приложением терминала C от Swift. Я успешно интегрировал исходный код и связал заголовки от C до Swift. Код компилируется и запускается из бета-версии Xcode 6.3. Я переименовал основную точку входа приложения терминала:

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

тем не менее, я изо всех сил пытаюсь передать аргументы от SWIFT к этой функции C. Моя задача-преобразовать аргументы в правильный формат. Типичный ввод от Swift будет выглядеть например:

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

Я пробовал возиться с" cStringUsingEncoding(NSUTF8StringEncoding) "и" withUnsafePointer", но пока не повезло. Любая помощь очень ценится!

2 ответов


функция 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() }
// Call C function:
let result = initialize(Int32(args.count), &cargs)
// Free the duplicated strings:
for ptr in cargs { free(ptr) }

Он использует тот факт, что в strdup() быстрая строка автоматически преобразуется в строку C, как объясняется в строковое значение для UnsafePointer поведение параметра функции.


основываясь на ответе Мартина, если вы обнаружите, что делаете это много, вы можете обернуть 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() } + [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], .baseAddress)
}