简体   繁体   English

如何将Swift字符串数组传递给带有char **参数的C函数

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

I'm trying to interact with an old C terminal app from Swift. 我正在尝试与Swift的旧C终端应用程序进行交互。 I've successfully integrated the source code and bridged the headers from C to Swift. 我已经成功集成了源代码,并将标头从C桥接到Swift。 The code compiles and runs from Xcode 6.3 beta. 该代码从Xcode 6.3 beta编译并运行。 I've renamed the terminal app's main entry point to: 我已将终端应用程序的主要入口点重命名为:

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

Nevertheless, I'm struggling to pass the arguments from Swift to this C function. 不过,我正在努力将Swift的参数传递给此C函数。 My challenge is to convert the arguments in the right format. 我的挑战是将参数转换为正确的格式。 Typical input from Swift would look like: Swift的典型输入如下所示:

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

I've tried messing with "cStringUsingEncoding(NSUTF8StringEncoding)" and "withUnsafePointer", but no luck so far. 我试过弄乱“ cStringUsingEncoding(NSUTF8StringEncoding)”和“ withUnsafePointer”,但到目前为止还没有运气。 Any help is greatly appreciated! 任何帮助是极大的赞赏!

The C function C函数

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

is mapped to Swift as 映射为Swift

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 . 它使用以下事实:在strdup($0) ,Swift字符串$0自动转换为C字符串,如UnsafePointer <UInt8>函数参数行为的字符串值中所述

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 : 基于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)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM