我意识到那里有“如何将char[]
/ char*
转换为Swift Sting”问题的上百万种形式,以及它们的反形式,所有这些都已被提出并回答。
我不是问这个。
在Swift中,我要做的就是简单地将C char
数组的地址(通过C函数获得)传递给另一个C函数的C char*
指针参数。 / p>
具体来说,我正在尝试复制以下C代码,其中将char
字段中包含的stat.f_mntonname
数组的地址作为getattrlist(const char*, ...)
调用的第一个参数传递:
// Get volume stat
const char* path = ...;
struct statfs volStat;
if (statfs(path,&volStat)==-1) { error }
// statfs has the mount point of the volume; use that to get attributes
struct attrlist request;
// ... set up request here
struct volAttrs {
// ... response values
}
if (getattrlist(volStat.f_mntonname,&request,&volAttrs,sizeof(volAttrs),FSOPT_NOFOLLOW)==-1) { error }
问题似乎是Swift将stat.f_mntonname
字段而不是数组解释为包含MAXPATHLEN
个数量的Int8
值的元组;换句话说,(Int8,Int8,Int8,Int8,Int8,...,Int8)
。
在互联网上闲逛很多次之后,我终于找到了解决方法:
var volStat = statfs()
guard statfs(fileURL.path, &volStat) != -1 else {
ErrorExit(cause: "statfs")
}
var attrRequest = attrlist()
// set up getattrlist request ...
var attrs = XtraVolumeAttrs()
guard getattrlist(UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN)),
&attrRequest,
&attrs,
MemoryLayout<XtraVolumeAttrs>.size,
UInt32(FSOPT_NOFOLLOW)) != -1 else {
ErrorExit(cause: "getattrlist")
}
所以魔术UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN)
似乎完成了将char[MAXPATHLEN]
数组转换为char*
的任务,但是男孩是丑陋,不直观的,并且-如果我说实话—我什至不确定这是正确的(除了代码有效的事实之外)。
我觉得必须有一个更好的方法,我希望有人能发布它。
答案 0 :(得分:1)
这很丑陋,因为Swift将C数组作为元组导入,并且不会自动转换为数组或指针。
正如Hamish所指出的那样,UnsafeRawPointer(&volStat.f_mntonname.0)
的使用是不正确的,因为从初始值设定项返回时,创建的指针可能无效。
一个安全的版本是
let retval = withUnsafeBytes(of: volStat.f_mntonname) {
getattrlist($0.bindMemory(to: Int8.self).baseAddress, /* other args */)
}
在覆盖元组原始字节的“缓冲区指针”上调用bindMemory()
,因此我们不必显式指定容量。