一个指向 Swift 字符串的 C 字符串表示的指针是通过以下方式获得的
s.withCString { cStringPtr in
callCFunction(cStringPtr)
}
但是有两个问题:第一,指针指向的存储是不可变的。如果 C 函数被声明为采用 achar *
但实际上并没有改变字符串(即,如果它应该被声明为采用const char *
参数),那么您可以使指针可变
s.withCString { cStringPtr in
let mutableCStringPtr = UnsafeMutablePointer(mutating: cStringPtr)
callCFunction(mutableCStringPtr)
}
但是这个指针仍然指向相同的(不可变的)存储,即如果 C 函数改变 C 字符串,这会导致未定义的行为。
这种方法的第二个问题是指针只对闭包的执行有效。您不能获取指针并将其保存以供以后使用。这将是未定义的行为:
let mutablePointer = s.withCString { cStringPtr in
UnsafeMutablePointer(mutating: cStringPtr)
}
// Use `mutablePointer` later.
对于更长的生命周期(即包装实例的生命周期),必须分配内存并复制 C 字符串。例如,这可以通过以下方式完成strdup()
:
class Wrapper {
var cStringPtr: UnsafeMutablePointer<CChar>
init(s: String) {
guard let cStringPtr = strdup(s) else {
// Handle "no memory" error ...
}
self.cStringPtr = cStringPtr
}
deinit {
free(cStringPtr)
}
}
(如果您想知道为什么可以直接将 Swift 字符串传递给strdup()
,请参阅字符串值到 UnsafePointer<UInt8> 函数参数行为。)