Указатель на строковое представление C строки Swift получается с помощью
s.withCString { cStringPtr in
callCFunction(cStringPtr)
}
, но есть две проблемы: во-первых, хранилище, на которое указывает указатель, не является изменяемым. Если функция C объявлена как принимающая char *
, но фактически не изменяющая строку (т.е. если она должна быть объявлена как принимающая аргумент 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 Поведение параметра функции .)