简体   繁体   English

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

[英]Convert a C String Array to a Swift String Array

I am not familiar with a way to convert a two dimensional array from C to an array of Strings which I can use in Swift.我不熟悉将二维数组从 C 转换为可以在 Swift 中使用的字符串数组的方法。 As far as I know there is no quick and easy way to do this in Swift.据我所知,在 Swift 中没有快速简便的方法来做到这一点。

This is the header of my C function:这是我的 C 函数的标题:

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

I tried the following:我尝试了以下方法:

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

(I have this code from Martin R: https://stackoverflow.com/a/38422783/10269733 . Unfortunately it doesn't work anymore in Swift 4.2) (我有来自 Martin R 的这段代码: https : //stackoverflow.com/a/38422783/10269733 。不幸的是,它在 Swift 4.2 中不再起作用了)

I am searching for a solution for this problem all day, therefore I am open for any kinds of creative ideas!我整天都在寻找这个问题的解决方案,因此我愿意接受任何类型的创意!

EDIT:编辑:

This code works perfectly这段代码完美运行

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

The problem is not in the Swift code (or related to any Swift 4.2 changes).问题不在于 Swift 代码(或与任何 Swift 4.2 更改相关)。 The real problem is that the C function returns the “2-dimensional array” variable真正的问题是 C 函数返回“二维数组”变量

char paths[FILES_MAX][PATH_MAX];

as a char ** to the caller – but that are incompatible types: one is an array of arrays (with all characters being in contiguous memory), the other is a pointer to a pointer.作为调用者的char ** - 但这是不兼容的类型:一个是数组数组(所有字符都在连续内存中),另一个是指向指针的指针。 There should be a compiler warning like应该有一个编译器警告,比如

incompatible pointer types returning 'char [...][...]' from a function with result type 'char **'不兼容的指针类型从结果类型为“char **”的函数返回“char [...][...]”

You could return paths from the function if you declare something like如果你声明类似的东西,你可以从函数返回paths

typedef char PathName[PATH_MAX];

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

But that would be imported to Swift as但这将被导入到 Swift 中

typealias PathName = (Int8, Int8, ... , Int8)

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

where PathName is a tuple of PATH_MAX characters – quite cumbersome to use from Swift!其中PathNamePATH_MAX字符的元组——在 Swift 中使用起来非常麻烦! Another problem is that the caller does not know how many arrays elements have been filled.另一个问题是调用者不知道已经填充了多少个数组元素。

Better define paths as an array of char pointers:更好地将paths定义为char指针数组:

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

and fill it with a NULL-terminated list of char pointers.并用一个以 NULL 结尾的char指针列表填充它。 Here is a over-simplified example:这是一个过于简化的例子:

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

In your real application you do not add string literals, so you'll probably have to duplicate the strings在您的实际应用程序中,您不会添加字符串文字,因此您可能必须复制字符串

    paths[j] = strdup(someString);

which means that at some point the strings must be free() d again, to avoid memory leaks.这意味着在某些时候字符串必须再次free() d,以避免内存泄漏。

credits to " https://oleb.net/blog/2016/10/swift-array-of-c-strings/ "归功于“ https://oleb.net/blog/2016/10/swift-array-of-c-strings/

C: C:

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

Apart from headers/bridging:除了标题/桥接:

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

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

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