swift cstring

Trabajar con cadenas C en Swift, o: Cómo convertir UnsafePointer<CChar> a CString



(1)

Swift 1.1 (o quizás antes) tiene un puente de cadena C aún mejor:

let haystack = "This is a simple string" let needle = "simple" let result = String.fromCString(strstr(haystack, needle))

El tipo CString se ha ido por completo.

Mientras jugaba con las funciones de la Biblioteca C estándar en Swift, encontré problemas al pasar las cadenas C alrededor. Como un ejemplo simple (solo para demostrar el problema), la función de la biblioteca de C estándar

char * strdup(const char *s1);

está expuesto a Swift como

func strdup(_: CString) -> UnsafePointer<CChar>

lo que significa que el valor de retorno de strdup() no se puede pasar a otra strdup() a 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

Mi pregunta es: ¿Cómo crear un Swift CString desde un UnsafePointer<CChar> , para que la cadena C devuelta por una función de biblioteca estándar pueda pasarse a otra función?

La única forma que pude encontrar es (usando el código de ¿Cómo convertir una cadena a una cadena CS en el lenguaje Swift? ):

let s2a = String.fromCString(s2).bridgeToObjectiveC().UTF8String let s3 = strdup(s2a)

Pero no encuentro esto satisfactorio por dos razones:

  • Es demasiado complicado para una tarea sencilla.
  • (Razón principal :) Las conversiones anteriores solo funcionan si la cadena C es una cadena UTF-8 válida; de lo contrario, falla con una excepción de tiempo de ejecución. Pero una cadena C es una secuencia arbitraria de caracteres, delimitada por un carácter NUL.

Observaciones / antecedentes: por supuesto, son preferibles las funciones de alto nivel que utilizan estructuras de datos de alto nivel como Swift String o Objective-C NSString . Pero hay funciones BSD en la biblioteca estándar de C que no tienen una contraparte exacta en los marcos de trabajo de Foundation.

Encontré este problema al intentar responder Accediendo al directorio temporal en Swift . Aquí, mkdtemp() es una función BSD para la cual no existe un reemplazo exacto de NSFileManager (que yo sepa). mkdtemp() devuelve un UnsafePointer<CChar> que se debe pasar a la función stringWithFileSystemRepresentation que toma un argumento CString .

Actualización: a partir de Xcode 6 beta 6, este problema ya no existe porque se ha simplificado el mapeo de C-Strings en Swift. Solo puedes escribir

let s1 = "abc" // String let s2 = strdup(s1) // UnsafeMutablePointer<Int8> let s3 = strdup(s2) // UnsafeMutablePointer<Int8> let s4 = String.fromCString(s3) // String