Code du port C avec de nombreux typecasts vers Swift

Swift vous permet d'appeler normalement les appels de la bibliothèque C existants et les appels système. C'est correct du point de vue de l'utilisation des actifs passés, mais comme Swift est plus strict de type que C, il n'est pas rare d'avoir des difficultés à appeler les fonctions C.

Cette fois, j'ai réécrit le troisième argument start_routine de pthread_create de la fonction C à la fermeture Swift. J'espère qu'il sera utile de voir ce qu'il advient du code qui est typé en C dans Swift.

(Parce que je suis un débutant de Swift, faites-le moi savoir s'il y a des erreurs)

Connaissances préalables

pthread_create crée un nouveau thread et passe le pointeur de fonction de la fonction à exécuter dans le nouveau thread avec le troisième argument start_routine. Les arguments de la fonction et les valeurs de retour sont void *, donc si vous souhaitez utiliser différents types d'arguments et de valeurs de retour, vous devez effectuer un transtypage à la fois sur l'appelant et l'appelé.

C'est une idée de type C de faire quoi que ce soit «vide *», mais bien sûr cela ne va pas bien avec Swift.

Code source C d'origine

Cette fois, je voulais utiliser une fonction qui prend ʻintetchar ** comme arguments et renvoie ʻint (en bref, c'est une fonction main) de pthread_create, donc j'ai utilisé une fonction wrapper pour cela. Je l'ai écrit en C.

void *pthread_main_routine(void *_arg)
{
    void **arg = (void **)_arg;
    int argc = (int)arg[0];
    char **argv = (char**)arg[1];
    void *retval = (void *)(long)orig_main(argc, argv);
    return retval;
}

Du côté Swift, cela s'appelait comme suit.

    var thread_arg = [
        UnsafeMutablePointer<Void>(bitPattern: args.pointers.count-1),
        UnsafeMutablePointer<Void>(args.pointers)
    ]
    pthread_create(&thread, nil, pthread_main_routine, &thread_arg)

J'ai essayé de le réécrire avec la fermeture de Swift

Cela fonctionnait également dans le code ci-dessus, mais pour diverses raisons, j'ai remplacé la fonction C par une fermeture Swift.

    typealias VoidPtr = UnsafeMutablePointer<Void>
    typealias VoidPtrArray = [UnsafeMutablePointer<Void>]
    typealias CharPtrArray = [UnsafeMutablePointer<CChar>]
    let thread_arg = [
        unsafeBitCast(args.pointers.count-1, VoidPtr.self),
        unsafeBitCast(args.pointers, VoidPtr.self),
    ]
    pthread_create(&thread, nil, {_arg in
        let arg = unsafeBitCast(_arg, VoidPtrArray.self)
        let argc = Int32(unsafeBitCast(arg[0], Int.self))
        let argv = unsafeBitCast(arg[1], CharPtrArray.self)
        let retval = unsafeBitCast(Int(orig_main(argc, argv)), VoidPtr.self)
        return retval
        }, unsafeBitCast(thread_arg, VoidPtr.self))

J'ai réussi à faire quelque chose qui fonctionne avec beaucoup de ʻunsafeBitCast`, mais cela s'est avéré assez fastidieux et difficile à lire. Le code plus facile à écrire en C doit être écrit en C.

Soit dit en passant, veuillez noter que le contenu à transmettre est légèrement modifié selon que le tableau Swift est converti en «void *» ou «char **» en «void *» dans les deux codes.

Réclamations, etc.

La gestion des fonctions C dans Swift2 n'est pas bonne, et seul le nom de la fonction globale lui-même ou le littéral de fermeture peut être placé dans le troisième argument de ce pthread_create. Si vous affectez une fonction à une variable et donnez cette variable comme argument, vous obtiendrez une erreur de compilation comme suit.

A C function pointer can only be formed from a reference to a 'func' or a literal closure

De plus, n'écrivez pas de code qui dépend de l'environnement, même s'il s'agit d'un littéral de fermeture. Par exemple, référencer une variable d'instance à partir de la fermeture entraînera une erreur de compilation comme indiqué ci-dessous.

A C function pointer cannot be formed from a closure that captures context

Je pense que ce dernier ne peut pas être aidé, mais qu'en est-il du premier? Je me sens comme ça. J'espère que Swift3 sera plus facile à manipuler ici.

Recommended Posts

Code du port C avec de nombreux typecasts vers Swift
[swift5] Comment changer la couleur de TabBar ou la couleur de l'élément de TabBar avec le code
Convertissez une chaîne en un tableau caractère par caractère avec Swift
Transition vers un contrôleur de vue avec Swift WebKit
Comment obtenir l'ID d'un utilisateur qui s'est authentifié avec Firebase dans Swift
Comment implémenter UICollectionView avec du code uniquement dans Swift
Ajoutez un package Swift local à votre projet avec Swift PM
Une histoire à laquelle j'étais accro avec toString () d'Interface qui était proxy avec JdkDynamicAopProxy
Une série d'étapes pour créer des livrables pour les portefeuilles avec Rails
Comment déplacer une autre classe avec une action de bouton d'une autre classe.
Un mémo pour démarrer la programmation Java avec VS Code (version 2020-04)
Passer le caractère de langage C * à Swift
Traitement inutile des collections - je veux vous donner une chance d'écrire du bon code. 5 [Exemple de refactoring C #]
Essayez d'imiter l'idée d'un tableau à deux dimensions avec un tableau à une dimension
Une histoire sur la connexion à un serveur CentOS 8 avec un ancien Ansible
Créer un compilateur C à utiliser avec Rust x CLion avec Docker
Exemple de code pour le test unitaire d'un contrôleur Spring Boot avec MockMvc
[Avec un exemple de code] Les bases de Spring JDBC apprises avec l'application Blog
Comment ouvrir un fichier de script à partir d'Ubuntu avec du code VS
[Swift] Comment envoyer une notification
Être conscient du code facile à lire
Appeler les fonctions du langage C depuis Swift
Convertir le tableau 2D de Swift en tableau 2D de C
Un enregistrement de la configuration d'un environnement de développement Java avec Visual Studio Code
[iOS] J'ai essayé de créer une application de traitement de type insta avec Swift
les rails c ne démarrent pas et un grand nombre d'erreurs de ligne se produisent
Comment créer une application avec un mécanisme de plug-in [C # et Java]
[Swift] Convertit un entier de type UInt64 en [UInt8]
Convertir le langage C en JavaScript avec Emscripten
Lier le code Java et C ++ avec SWIG
[Swift 5] Implémentation de l'enregistrement des membres dans Firebase
Comment appeler le code Swift 5.3 depuis Objective-C
Extraire une partie d'une chaîne en Ruby
[Swift5] Comment créer un écran de démarrage
Comment exécuter Blazor (C #) avec Docker
J'ai essayé d'implémenter une fonction équivalente à Felica Lite avec HCE-F d'Android
Volume qui souhaite utiliser de nombreux opérateurs logiques dans l'instruction if
Envoyez des notifications à Slack avec la version gratuite de sentry (en utilisant lambda)
Rails6 Je veux créer un tableau de valeurs avec une case à cocher
Briser de force le problème C "* 3 ou / 2" de [AtCoder Problem-ABC100] avec Java [Code]
[Spring Boot] Si vous utilisez Spring Boot, il était pratique d'utiliser de nombreux utilitaires.
J'ai essayé de cloner une application Web pleine de bugs avec Spring Boot
De la création d'un projet Spring Boot à l'exécution d'une application avec VS Code
[Swift] J'ai déjà beaucoup d'informations, mais j'ai essayé de résumer le casting (comme, comme!, Comme?) À ma manière.