IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Comment écrire un wrapper C++ pour une bibliothèque C ?


Sujet :

C++

  1. #1
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut Comment écrire un wrapper C++ pour une bibliothèque C ?
    Bonjour à tous,
    Je doit en ce moment utiliser une bibliothèque développée en C, mais mon projet principal est en C++. Je souhaiterais donc faire un petit wrapper C++ de cette bibliothèque et je m'interroge sur la meilleure manière de faire.

    Elle se nomme libParse et je l'obtiens sous la forme d'un répertoire contenant un paquet de header et de fichiers sources. J'ai donc tous les choix possibles, modifier les sources, en faire une dll, en faire une lib statique, l'intégrer directement dans mon projet etc.

    Dans un premier temps, j'ai naivement tenté de créer un projet C++ organisé comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Projet libParseWrapper 
      rep C
         rep header // header de libParse en C
         rep source // source de libParse en C
      rep header // header de mon wrapper CPP
      rep source // source de mon wrapper CPP
    Car après tout le C++ est rétro-compatible avec le C, right ? (indice : ahahahah)
    J'ai compilé et ...
    Malheureusement, le code C est saturé de chose de ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void addTag (char * dst, char * tagname) ; // déclaration
    //...
     
    unsigned char buffer [64];
    //...
     
    addTag (buffer , "tag");
    qui compile sans problème avec VC2005 en mode C (option "Compile as C code"). Par contre en mode C++, la sanction est immédiate :
    cannot convert parameter 1 from 'unsigned char [64]' to 'char *'
    Alors bien sur, je peux supprimer l'erreur en écrivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    addTag ((char*)buffer, "tag");
    Mais le problème, c'est qu'il y a plusieurs centaines d'erreurs du même tonneau éparpillées dans le code

    Je n'ai pas trouvé le moyen de désactiver ce genre d'erreur en C++, rajouter des centaines de cast risque de prendre un temps fou et j'ai un peu peur de me lancer dans une solution à base de dll....
    Quelle est selon vous la meilleure manière de faire ?

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Selon moi, la meilleure, mais pas forcément la moins chère, rentable uniquement si tu vas beaucoup l'utiliser :
    - Imprègne toi de l'interface de cette bibliothèque en C
    - Écrit une interface à la mode C++ (RAII, encapsulation, gestion de la mémoire) qui réponde aux même besoins que ta bibliothèque C
    - Implémente cette interface dans une bibliothèque C++ mais utilisant la bibliothèque C (compilée en C) pour faire le boulot.
    - Utilise cette bibliothèque.

    Après, statique ou dynamique, je dirais que sauf pour des besoins de plug-ins, le statique est plus simple à gérer.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Par contre en mode C++, la sanction est immédiate :
    cannot convert parameter 1 from 'unsigned char [64]' to 'char *'
    Un truc que je comprend pas. Les fichiers sources de ta bibliothèque ont une extension C et doivent compiler avec le compilateur C par défaut ?
    Ensuite quand tu l'utilise dans un source C++ (ton wrapper), tu peux faire du code C++ correc' ? (modulo extern "C" dans les headers).

  4. #4
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Selon moi, la meilleure, mais pas forcément la moins chère, rentable uniquement si tu vas beaucoup l'utiliser :
    - Imprègne toi de l'interface de cette bibliothèque en C
    - Écrit une interface à la mode C++ (RAII, encapsulation, gestion de la mémoire) qui réponde aux même besoins que ta bibliothèque C
    Euuu oui, c'est surement le cas idéal. Mais vu les contraintes de temps, le plan c'était plutôt de wrapper les quelques fonctions qui font office de point d'entrée et voilà

    - Implémente cette interface dans une bibliothèque C++ mais utilisant la bibliothèque C (compilée en C) pour faire le boulot.
    - Utilise cette bibliothèque.
    Mais justement, c'est sur ce problème que je m'échine depuis quelques heures !
    Et j'ai finalement réussi !
    Donc, pour les suivants, voici la manoeuvre à suivre :

    Dans un premier projet libC, on place notre lib... en C.
    Ce projet compile en C et génère une librairie statique (.lib)
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #ifndef CSTUFF_H
    #define CSTUFF_H
     
    void parse(char * file) {}
     
    #endif
    Et dans un autre projet, libCPP, on place notre wrapper C++.
    Ce projet compile en C++ et doit être linké avec le .lib généré depuis libC.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #ifndef CPPSTUFF_H
    #define CPPSTUFF_H
     
    #include "CStuff.h"
     
    void parse(const std::string& file)
    {
       parse((char*) file.c_str());
    }
     
    #endif
    On compile et .... erreur ! Le linker se gauffre :
    "error LNK2019: unresolved external symbol "void __cdecl parse(char *)"

    La raison semble être :
    La convention d'appel des fonctions C et C++ sont différentes.
    Ou : La décoration des fonctions C et CPP sont différentes.
    Ou peut-être les deux.
    Ou peut être que les deux veulent dire la même chose.

    Toujours est-il que la solution est de placer ce bout de code tout en haut de chaque header de la libC :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #ifdef __cplusplus
     extern "C" {
    #endif
    et ce bout de code tout en bas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    #ifdef __cplusplus
     }
    #endif
    Grace à cette manip les deux compilateurs (C et C++) peuvent lire le fichier CStuff.h. Le compilateur C va simplement ignorer les instructions contenues entre les #ifdef __cplusplus #endif car aucun compilateur C ne définit le symbole __cplusplus, alors que le compilateur C++ va comprendre grâce à extern "C" {} qu'il doit utiliser les fonctions qui suivent à la mode C.

  5. #5
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Damned, maintenant que je connais la réponse, je m'appercois qu'un item de la faq traite de la question.

    J'avais pourtant tenté un coup de google "developpez faq utiliser librairies C en C++", qui ne donne rien, il fallait en fait écrire "developpez faq utiliser bibliothèques C en C++" :smileyfacepalm:

    Y pouvait pas utiliser le terme librairie comme tout le monde ? (même si c'est un anglicisme vilain )

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Salut,

    Tu peux aussi, pour éviter de modifier les en-têtes de la bibliothèque C, directement avoir recours à un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    extern "C"
    {
       #include "Cstuff.h"
       /* et toutes les en-têtes propres au C */
    }
    dans tes en-tête propres au C++
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] Comment écrire un service web pour récupérer un champ d'une base de données
    Par mallsoul dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 04/10/2012, 19h23
  2. Réponses: 0
    Dernier message: 31/08/2007, 19h29
  3. Comment écrire dans le champ d'une structure?
    Par JRmon42 dans le forum MATLAB
    Réponses: 2
    Dernier message: 04/04/2007, 13h16
  4. script configure pour une bibliothèque
    Par spidermario dans le forum Shell et commandes GNU
    Réponses: 1
    Dernier message: 10/03/2007, 20h00
  5. Réponses: 1
    Dernier message: 09/02/2006, 12h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo