Как передать массив строк 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)
}