Во время игры со стандартными функциями библиотеки 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