Travailler avec des chaînes C dans Swift, ou: Comment faire pour convertir UnsafePointer<CChar> pour CString
Tout en jouant avec le Standard de fonctions de la Bibliothèque C dans Swift, je suis tombé sur des problèmes
en passant C des chaînes autour de. Un exemple simple (juste pour illustrer le problème), la Bibliothèque Standard C de la fonction
char * strdup(const char *s1);
est exposé à Swift comme
func strdup(_: CString) -> UnsafePointer<CChar>
ce qui signifie que la valeur de retour de strdup()
ne peut pas être transmis à une autre strdup()
appel:
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 le C de la chaîne retournée par une fonction de la bibliothèque standard peut être transmis à une autre fonction?
La seule façon que j'ai pu trouver est (en utilisant le code de Comment convertir une Chaîne de caractères à une CString de la Swift de la Langue?):
let s2a = String.fromCString(s2).bridgeToObjectiveC().UTF8String
let s3 = strdup(s2a)
Mais je ne trouve pas cela satisfaisant pour deux raisons:
- C'est trop compliqué pour une simple tâche.
- (Raison:) ci-dessus conversions ne fonctionne que si la chaîne C est un UTF-8 valide
chaîne, sinon elle échoue avec une exception d'exécution. Mais une chaîne C est un arbitraire
séquence de caractères délimitées par un caractère NUL.
Remarques/Contexte: bien sûr, des fonctions de haut niveau à l'aide de haut-niveau des structures de données comme Swift String
ou Objective-C NSString
sont préférables. Mais il y a des fonctions BSD dans le
Bibliothèque Standard C qui n'ont pas un équivalent exact dans la Fondation des cadres.
Je suis tombé sur ce problème tout en essayant de répondre à L'accès au répertoire temp en Swift.
Ici, mkdtemp()
est un BSD fonction pour laquelle aucune NSFileManager
de remplacement existe
(autant que je sache).
mkdtemp()
renvoie une UnsafePointer<CChar>
qui doit être transmis à la
NSFileManager
fonction stringWithFileSystemRepresentation
qui prend un CString
argument.
Mise à jour: de Xcode 6 beta 6, ce problème n'existe plus car la cartographie de C-Strings en Swift a été simplifiée. Il vous suffit d'écrire
let s1 = "abc" //String
let s2 = strdup(s1) //UnsafeMutablePointer<Int8>
let s3 = strdup(s2) //UnsafeMutablePointer<Int8>
let s4 = String.fromCString(s3) // String
- Merci à l'anonyme downvoter qui m'a rappelé, à porter la question à jour 🙂
Vous devez vous connecter pour publier un commentaire.
Swift 1.1 (ou peut-être plus tôt) a encore mieux chaîne C de transition:
La
CString
type est complètement perdu.st.withCString({ $0 })
est nettement plus élégant quebridgeToObjectiveC().UTF8String
. - MaisString.fromCString(up)
déjà échoue avec une exception d'exécution siup
n'est pas une chaîne UTF-8, donc ce problème n'est pas résolu. EssayezCStringFromUnsafeCChar(foo())
oùfoo()
est une fonction C de retourner une chaîne C qui n'est pas UTF-8 valide. Par exemple:char *foo(void) { static char buf[] = { -1, 0}; return buf; }
.CString
àUnsafePointer<CChar>
.reinterpretCast()
fonctionne parfaitement, j'ai pu l'appliquer ici: stackoverflow.com/a/24290234/1187415. Merci encore!