将C字符串数组转换为Swift字符串数组

时间:2018-09-26 16:33:13

标签: arrays swift

我不熟悉将二维数组从C转换为可在Swift中使用的Strings数组的方法。据我所知,在Swift中没有快速简便的方法可以做到这一点。

这是我的C函数的标题:

char **getAllFilePaths(const char path []);

我尝试了以下操作:

//Get the pointer of the String array
if var ptr = getAllFilePaths(a) {

     //Check if the current String is null
     while let s = ptr.pointee {

        //Copy the String into an array
        a_paths.append(String(cString: s)) //<- Crash: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

        //Go to the next adress
        ptr += 1
     }

    print(a_paths)
}

(我有Martin R的这段代码:https://stackoverflow.com/a/38422783/10269733。不幸的是,它在Swift 4.2中不再起作用了)

我整天都在寻找解决方案,因此,我愿意接受各种创意!

编辑:

此代码可完美运行

char paths [FILES_MAX][PATH_MAX];
static size_t i = 0;

char **getAllFilePaths(const char path []){
    PrintFile(path);

    size_t j;

    for(j = 0; j < i; j++){
        printf("%s\n", paths[j]);
    }

    return paths;
}

2 个答案:

答案 0 :(得分:0)

问题不在Swift代码中(或与任何Swift 4.2更改有关)。 真正的问题是C函数返回“二维数组”变量

char paths[FILES_MAX][PATH_MAX];

作为对呼叫者的char ** –但不兼容的类型:一种是 数组数组(所有字符都在连续内存中),另一个是指向指针的指针。应该有类似

的编译器警告
  

不兼容的指针类型从结果类型为'char **'的函数返回'char [...] [...]'

如果您声明类似的内容,您可以从函数中返回paths

typedef char PathName[PATH_MAX];

PathName *getAllFilePaths(const char path []) { ... }

但是它将作为

导入到Swift中。
typealias PathName = (Int8, Int8, ... , Int8)

public func getAllFilePaths(_ path: UnsafePointer<Int8>!) -> UnsafeMutablePointer<PathName>!

其中PathNamePATH_MAX个字符的元组 –非常麻烦 从Swift使用!另一个问题是呼叫者不知道 已经填充了多少个数组元素。

更好地将paths定义为char指针的数组:

static char *paths[FILES_MAX] = { NULL };

,并用char指针的NULL终止列表填充。这里有一个 过于简化的示例:

char **getAllFilePaths(const char path []) {
    paths[0] = "foo";
    paths[1] = "bar";
    paths[2] = NULL;
    return paths;
}

在实际的应用程序中,您不会添加字符串 literal ,因此您可能会 必须复制字符串

    paths[j] = strdup(someString);

这意味着在某些时候必须再次free()字符串,以避免 内存泄漏。

答案 1 :(得分:0)

https://oleb.net/blog/2016/10/swift-array-of-c-strings/”的信用额

C:

int myCFunc(char *const argv[], size_t howmany )
{
    int i;
    for(i=0; i < howmany; i++){
        printf("\n%s", argv[i]);
    }
    return 1;
}

除了标题/桥接:

// Swift:

import Foundation

public func withArrayOfCStrings<R>(
    _ args: [String],
    _ body: ([UnsafeMutablePointer<CChar>?]) -> R
) -> R {
    var cStrings = args.map { strdup($0) }
    cStrings.append(nil)
    defer {
        cStrings.forEach { free($0) }
    }
    return body(cStrings)
}


func goLowlevel(arguments: [String]) -> Int {

    let count = arguments.count
    return withArrayOfCStrings(arguments) {
        argv in

        myCFunc(argv, count)
        return 10
    }
}


let arr = ["AA", "BBB", "CCCC"]
goLowlevel(arguments: arr)