How to pass an array of Swift strings to a C function taking a char ** parameter

末鹿安然 提交于 2019-11-26 14:46:41
Martin R

The C function

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

is mapped to Swift as

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

This is a possible solution:

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

It uses the fact that in strdup($0) the Swift string $0 is automatically converted to a C string, as explained in String value to UnsafePointer<UInt8> function parameter behavior.

Building on Martin’s answer, if you find yourself doing this a lot, you could wrap the dup/free part into a function in a similar style to 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)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!