En jouant avec les fonctions de la bibliothèque C standard dans Swift, j'ai rencontré des problèmes lors du passage des chaînes C. Comme exemple simple (juste pour illustrer le problème), la fonction de bibliothèque C standard
char * strdup(const char *s1);
est exposé à Swift as
func strdup(_: CString) -> UnsafePointer<CChar>
ce qui signifie que la valeur de retour de strdup()
ne peut pas être transmise à un autre appel 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
Ma question est: Comment créer un Swift CString
à partir d'un UnsafePointer<CChar>
, de sorte que la chaîne C renvoyée par une fonction de bibliothèque standard puisse être passée à une autre fonction?
La seule façon que j'ai pu trouver est (en utilisant le code de Comment convertir une chaîne en CString dans la langue Swift? ):
let s2a = String.fromCString(s2).bridgeToObjectiveC().UTF8String
let s3 = strdup(s2a)
Mais je ne trouve pas cela satisfaisant pour deux raisons:
Remarques/Contexte: Bien sûr, les fonctions de haut niveau utilisant des structures de données de haut niveau comme Swift String
ou Objective-C NSString
sont préférables, mais il existe des fonctions BSD dans la bibliothèque C standard qui n'ont pas de contrepartie exacte dans les frameworks Foundation.
J'ai rencontré ce problème en essayant de répondre Accès au répertoire temporaire dans Swift . Ici, mkdtemp()
est une fonction BSD pour laquelle il n'existe pas de remplacement exact de NSFileManager
(pour autant que je sache). mkdtemp()
renvoie un UnsafePointer<CChar>
qui doit être passé à la fonction NSFileManager
stringWithFileSystemRepresentation
qui prend un argument CString
.
Mise à jour: Depuis Xcode 6 beta 6, ce problème n'existe plus car le mappage des chaînes C en Swift a été simplifié. Vous pouvez simplement écrire
let s1 = "abc" // String
let s2 = strdup(s1) // UnsafeMutablePointer<Int8>
let s3 = strdup(s2) // UnsafeMutablePointer<Int8>
let s4 = String.fromCString(s3) // String
Swift 1.1 (ou peut-être plus tôt) a un pontage de chaîne C encore meilleur:
let haystack = "This is a simple string"
let needle = "simple"
let result = String.fromCString(strstr(haystack, needle))
Le type CString
a complètement disparu.
La structure String dans Swift a une routine d'initialisation que vous pouvez utiliser comme:
let myString = String(cString: myUnsafePointer)
voir aussi init (cString: UnsafePointer)