Работа со строками C в Swift или: Как преобразовать UnsafePointer <CChar> в CString
Во время игры со стандартными функциями библиотеки C в Swift я столкнулся с проблемами
при прохождении C строк вокруг. В качестве простого примера (просто для демонстрации проблемы) функция Standard C Library
char * strdup(const char *s1);
подвергается воздействию Swift как
func strdup(_: CString) -> UnsafePointer<CChar>
что означает, что возвращаемое значение strdup()
не может быть передано другому вызову strdup()
:
let s1 : CString = "abc"
let s2 = strdup(s1) // OK, s2 is a UnsafePointer<CChar>
let s3 = strdup(s2) // error: could not find an overload for '__conversion' that accepts the supplied arguments
Мой вопрос: Как создать Swift CString
с UnsafePointer<CChar>
,
так что строка C, возвращаемая одной стандартной библиотечной функцией, может быть передана другой функции?
Единственный способ, которым я мог найти (с помощью кода из Как преобразовать String в CString на языке Swift?):
let s2a = String.fromCString(s2).bridgeToObjectiveC().UTF8String
let s3 = strdup(s2a)
Но я не считаю это удовлетворяющим по двум причинам:
- Это слишком сложно для простой задачи.
- (Основная причина:) Вышеперечисленные преобразования работают только в том случае, если строка C является допустимым UTF-8
string, в противном случае он завершится неудачей с использованием исключения времени выполнения. Но строка C является произвольной
последовательность символов, ограниченная символом NUL.
Примечания/Предпосылки: Конечно, предпочтительны высокоуровневые функции с использованием высокоуровневых структур данных, таких как Swift String
или Objective-C NSString
. Но есть функции BSD в
Standard C Library, которые не имеют точного аналога в рамках Foundation.
Я столкнулся с этой проблемой, пытаясь ответить Доступ к временному каталогу в Swift.
Здесь mkdtemp()
- это функция BSD, для которой не существует точной замены NSFileManager
(насколько я знаю).
mkdtemp()
возвращает a UnsafePointer<CChar>
, который должен быть передан в
NSFileManager
функция stringWithFileSystemRepresentation
, которая принимает значение CString
аргумент.
Обновление: с Xcode 6 beta 6 эта проблема больше не существует, потому что сопоставление C-строк в Swift было упрощено. Вы можете просто написать
let s1 = "abc" // String
let s2 = strdup(s1) // UnsafeMutablePointer<Int8>
let s3 = strdup(s2) // UnsafeMutablePointer<Int8>
let s4 = String.fromCString(s3) // String
Ответы
Ответ 1
Swift 1.1 (или, возможно, более ранний) имеет еще лучшее связывание строки C:
let haystack = "This is a simple string"
let needle = "simple"
let result = String.fromCString(strstr(haystack, needle))
Тип CString
полностью отсутствует.