[英]Convert a C String Array to a Swift String Array
我不熟悉将二维数组从 C 转换为可以在 Swift 中使用的字符串数组的方法。 据我所知,在 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;
}
问题不在于 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>!
其中PathName
是PATH_MAX
字符的元组——在 Swift 中使用起来非常麻烦! 另一个问题是调用者不知道已经填充了多少个数组元素。
更好地将paths
定义为char
指针数组:
static char *paths[FILES_MAX] = { NULL };
并用一个以 NULL 结尾的char
指针列表填充它。 这是一个过于简化的例子:
char **getAllFilePaths(const char path []) {
paths[0] = "foo";
paths[1] = "bar";
paths[2] = NULL;
return paths;
}
在您的实际应用程序中,您不会添加字符串文字,因此您可能必须复制字符串
paths[j] = strdup(someString);
这意味着在某些时候字符串必须再次free()
d,以避免内存泄漏。
归功于“ 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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.