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

Posted

技术标签:

【中文标题】如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数【英文标题】:How to pass an array of Swift strings to a C function taking a char ** parameter 【发布时间】:2015-04-06 10:09:33 【问题描述】:

我正在尝试与 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”,但到目前为止没有运气。非常感谢任何帮助!

【问题讨论】:

title 可能会“更好”,因为提到问题是 C 函数调用中的 char** 参数。 【参考方案1】:

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 中所述。

【讨论】:

谢谢,就像一个魅力。对于其他尝试做类似事情的人,我应该补充一点,C 从索引 1 而不是 0 开始传递参数向量。我将参数更新为:let args = ["", "-c", "1.2.3.4", " -p", "8000"]. 如果我有一个命令行游戏,你认为可以运行它并向它传递参数,然后将它的标准输出提取到文本区域,例如在 swift 中吗?还是我必须使用它的功能从头开始玩游戏? @马克 @AhmedNassar:据我所知,您无法在 ios 中运行外部程序。 不是外部的,我的项目中有 C 程序,我可以将参数传递给它的主函数吗? @AhmedNassar:用上述方法应该是可能的。您可能需要重命名 main 函数。【参考方案2】:

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

【讨论】:

以上是关于如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数的主要内容,如果未能解决你的问题,请参考以下文章

将 char 指针数组传递给函数

将字符串传递给 char 数组,然后在 C 中的位置 x 处修改 char 数组

如何将String类的字符串 赋值给Char数组

如何将String类的字符串 赋值给Char数组

将 c++ dll 的 char 指针数组传递给 c# 字符串

Swift 3 将 ArrayList 对象变量传递给字符串数组