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

Langage C++ Discussion :

Espace noms, DLL et C++


Sujet :

Langage C++

  1. #1
    Membre régulier
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Avril 2014
    Messages
    105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Avril 2014
    Messages : 105
    Points : 97
    Points
    97
    Par défaut Espace noms, DLL et C++
    Bonjour tout le monde,

    Je n'arrive pas à utiliser une dll lorsque je l'encapsule dans un espace nom. C'est comme si les liaisons se perdaient :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #ifdef ROOTERLIB_EXPORTS
    #define ROOTERLIB_API  __declspec(dllexport)
    #else
    #define ROOTERLIB_API __declspec(dllimport)
    #endif //ROOTERLIB_EXPORTS
     
        class ROOTERLIB_API CRooterLib {
        public:
            CRooterLib(void);       
        };

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #include "stdafx.h"
    #include "RooterLib.h"
    #include <iostream>
     
    using namespace std;
    CRooterLib::CRooterLib(){    }
    crée bien un .lib et dll que je peux utiliser dans un programme. Alors que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #ifdef ROOTERLIB_EXPORTS
    #define ROOTERLIB_API  __declspec(dllexport)
    #else
    #define ROOTERLIB_API __declspec(dllimport)
    #endif //ROOTERLIB_EXPORTS
     
    namespace MaClasse{
        class ROOTERLIB_API CRooterLib {
        public:
            CRooterLib(void);       
        };
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #include "stdafx.h"
    #include "RooterLib.h"
    #include <iostream>
     
    using namespace std;
    namespace MaClasse{
        CRooterLib::CRooterLib(){    }   
    }
    ne fonctionne pas. Lorsque j'essaye d'utiliser la DLL :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    using namespace std;
    using namespace MaClasse;
    int main()
    {
        int a;
        CRooterLib test;
    }

    J'obtiens les erreurs suivantes :

    Erreur LNK2019 symbole externe non rÚsolu "__declspec(dllimport) public: __cdecl MaClasse::CRooterLib::CRooterLib(void)" (__imp_??0CRooterLib@MaClasse@@QEAA@XZ) rÚfÚrencÚ dans la fonction main Utilisateur D:\Programmation\FramworkDLL\Utilisateur\Utilisateur\Utilisateur.obj 1 Link
    Erreur LNK1120 1 externes non rÚsolus Utilisateur D:\Programmation\FramworkDLL\Utilisateur\x64\Debug\Utilisateur.exe 1 Link


    Auriez-vous une explication?

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par awawawa Voir le message
    ... ...
    ne fonctionne pas. Lorsque j'essaye d'utiliser la DLL :
    ... ...
    J'obtiens les erreurs suivantes :

    Erreur LNK2019 symbole externe non rÚsolu "__declspec(dllimport) public: __cdecl MaClasse::CRooterLib::CRooterLib(void)" (__imp_??0CRooterLib@MaClasse@@QEAA@XZ) rÚfÚrencÚ dans la fonction main Utilisateur D:\Programmation\FramworkDLL\Utilisateur\Utilisateur\Utilisateur.obj 1 Link
    Erreur LNK1120 1 externes non rÚsolus Utilisateur D:\Programmation\FramworkDLL\Utilisateur\x64\Debug\Utilisateur.exe 1 Link
    Quelque chose m'échappe, au moment d'utiliser la dll, on ne peut pas avoir une erreur de lien. Ça semble être au moment de linker la lib? Et dans ce cas je ne vois pas ce qui pourrait bloquer.
    On pourrait essayer d'ajouter devant la définition du constructeur __declspec(dllexport) pour le "forcer" à exporter cette fonction

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Février 2007
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 37
    Points : 72
    Points
    72
    Par défaut
    Le code tel quel doit fonctionner, c'est probablement un problème de configuration, ie la lib n'est pas linké avec ton executable. Par exemple il essaie de link avec la précédente lib en version "sans namespace" ?

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

    Informations professionnelles :
    Activité : aucun

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

    Avant toute chose :

    1- un espace de nom qui s'appelle MaClasse c'est ... moyen moyen... Pourquoi pas l'appeler MonEspaceDeNom ou MaLib ces noms seraient déjà plus en rapport avec ce qu'il identifient, tu ne pense pas

    2- Fais moi le plaisir de virer cette directive using namespace std que je ne saurais voir (et qui, de plus, n'est absolument pas utile à la partie de code que tu nous présente):

    Cette directive a été spécialement ajoutée, au tout début de la normalisation, quand le comité a décidé de faire passer l'intégralité de la bibliothèque standard dans l'espace de noms std. Le problème, à l'époque, était qu'il existait déjà "de nombreux" projets développés en C++ (avant même que le langage ne soit normalisé), et qui utilisaient une version de la bibliothèque standard qui se trouvait dans ... l'espace de noms global.

    Il fallait donc faire en sorte que ces projets (développé avant la fin des années 90, de quand date la normalisation) puissent continuer à compiler en devant subir "un minium de modifications", car il était impensable de modifier tous les fichiers de tous les projets uniquement pour aller ajouter [c]std::[c] partout où cela s'avérait nécessaire.

    La chance étant qu'il y a généralement un fichier d'en-tête (config.h ) qui est inclus de manière systématique partout, et qu'en rajoutant cette directive dans ce fichier d'en-tête "global", n'importe quel projet pouvait continuer à compiler sans nécessiter "plus de modification que cela".

    Par contre, cette directive occasionne bien plus de problèmes qu'elle n'en résout, ne serait-ce que parce qu'elle brise purement et simplement l'espace de noms indiqué. Essaye simplement d'afficher une variable (du type que tu veux) appelée cout en utilisant cette directive, et tu sentiras ta douleur

    De plus, cette directive est apparue pour permettre à du code écrit avant la normalisation de continuer à compiler. La normalisation, elle est passée depuis plus de vingt ans à l'heure actuelle. On ne peut donc pas dire que le code écrit depuis le début des années 2000 date ... d'avant la normalisation

    Pour ton problème: les erreurs LNKxxx et celles qui te parlent de "symbole externe non résolu" sont typiquement des erreurs dues à l'éditeur de liens. C'est à dire, qu'elles sont dues à l'outil qui se charge normalement de regrouper l'ensemble des fichiers objets en un exécutable.

    Lorsque tu utilises une bibliothèque -- qu'elle soit statique ou dynamique -- il faut que tu indiques à l'éditeur de lien qu'il doit "aller voir dans la bibliothèque en question" s'il n'y trouve pas les symboles qui correspondent aux fonctions dont il a besoin.

    Pour les dlls, de manière spécifique, le plus facile est toujours de générer une "bibliothèque d'importation" (un .lib qui permettra à l'éditeur de liens de faire son taf), et de l'indiquer comme dépendance au même titre que "n'importe quelle autre bibliothèque statique"; le cas échéant, au travers de la directive #pragma comment(lib, "dll.lib") (en utilisant VC++ uniquement).

    Si cela ne convient pas (ce qui serait très domage), il reste toujours d'autres solutions plus barbares les unes que les autres dont je ne parlerai que contraint et forcé
    .
    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

  5. #5
    Membre régulier
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Avril 2014
    Messages
    105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Avril 2014
    Messages : 105
    Points : 97
    Points
    97
    Par défaut
    Bonjour tout le monde,

    Tout d’abord merci pour vos questions.

    Effectivement c'était un problème de lien avec un .lib. J'avais fait un truc un peu bâtard sous ms visual : j'ai fait des liaisons de dépendance et j'ai modifié les chemins vers les .lib. En reprenant le projet, tout semble à présent bien fonctionner.

    Fais moi le plaisir de virer cette directive using namespace std que je ne saurais voir
    @koala : si je te comprends bien il ne faut donc jamais utiliser using namespace std? Dans 80% des tutoriels et des cours les gens le font... dans le namespace std est à proscrire? Du coup de façon générale il faudrait proscrire l'utilisation de directive #using namespace quelque_chose? Un peu comme, j'ai cru comprendre, en python? Donc les espaces noms sont juste là pour éviter les ambiguïté et non rendre le code plus lisible?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par awawawa Voir le message
    @koala : si je te comprends bien il ne faut donc jamais utiliser using namespace std?
    Oui, tu me comprends bien... Et l'on peut même aller beaucoup plus loin, c'est carrément l'usage de la directive using namespace <n'importe quel espace de noms> qui est à proscrire.

    Cette pratique brise entièrement le systèmes d'espaces de noms, et produit plus de problèmes que ce qu'elle ne propose d'en résoudre.

    Dans 80% des tutoriels et des cours les gens le font...
    Je sais... Et cela fait pres de vingt ans que tous les professionnels tentent de faire valoir qu'il ne faut surtout pas l'utiliser
    dans le namespace std est à proscrire?
    Attention, cette directive ne place absolument pas les fonctionnalités que tu développes dans l'espace de noms.

    "Tout ce qu'elle fait", c'est dire au compilateur "si tu as besoin d'une fonctionnalité donnée, tu peux toujours aller voir si elle ne se trouve pas, à tout hasard dans l'espace de noms indiqué (std)"

    Et, de manière générale, il est -- en effet -- totalement interdit de rajouter des fonctionnalités dans l'espace de noms std, car cet espace de noms est strictement réservé aux fonctionnalités fournies par la bibliothèque standard

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Du coup de façon générale il faudrait proscrire l'utilisation de directive #using namespace quelque_chose?
    Oui, tout à fait... A ceci près qu'il n'y a pas de hashtag...
    Un peu comme, j'ai cru comprendre, en python?
    Attention, il y a une différence très nette entre la directive using namespace quelque_chose du C++ et la directive using un_module_quelconque du Python ou du java ! (ou de tout autre langage modulaire)...

    Pour faire simple, un espace de noms, c'est une espèce de "boite" dans laquelle tu peux regrouper les éléments "qui vont bien ensemble".

    Par exemple, tu pourrais créer une boite dans laquelle tu mettrais tous les outils, tous les ustensiles que tu utilises pour tes différentes activités.

    Mais cela voudrait dire que ton tournevis serait dans la même boite que ta faux, que ton racagnac ou que ton couteau "grand chef", ce qui
    • manquerait d'hygiène (l'huile qui a coulé sur ton racagnac quand tu as fait ta vidange risque de finir sur ton couteau "grand chef")
    • serait potentiellement dangereux (tu risque de te couper à la faux ou au couteau grand chef en voulant prendre le tournevis)
    • manquerait de précision (quand tu cuisine, tu n'as besoin ni d'un tournevis, ni d'une faux, ni d'un racagnac)

    On peut donc rajouter des "boites intermédiaires" :
    • une dans laquelle tu mettrais la faux et tous les outils de jardinage,
    • une autre dans laquelle tu mettrais tous les outils destinés à la mécanique et
    • une dernière dans laquelle tu mettrais tous les ustensiles de cuisine

    Et, bien sur, tu pourrais laisser, dans la boite "outils" mais hors de toute boite spécifique tous les outils qui ne sont pas forcément destinés à une activité particulière (marteau, tournevis, mètres, ...)

    Quand tu utilises la directive using namespace XXX, cela revient à ... renverser sur la table le contenu de la boite XXX.

    Si tu décidais de renverser sur la table ta boite "outils" tu verrais
    • tes tournevis
    • tes marteaux
    • tes mètres
    • la boite "jardinage"
    • la boite "cuisine"
    • la boite "mécanique"

    Et, bien sur, si tu décides de retourner, en plus, le contenu d'une de ces boites spécifiques, tu en viendrait à "mélanger" les outils "non spécifiques" avec ceux de la boite que tu aurais renversée.

    La directive using de python ou de java ne fonctionne pas du tout sous cette forme. Elle permet d'indiquer au compilateur / à l'interpréteur que l'on veut ... pouvoir utiliser le contenu du module indiqué.

    L'un dans l'autre, son usage est plus proche, en termes de résultats, de la directive (préprocesseur) #include <nom de fichier> du C et du C++
    Donc les espaces noms sont juste là pour éviter les ambiguïté et non rendre le code plus lisible?
    Effectivement, les espaces de noms sont -- d'abord et avant tout -- destinés à éviter les ambiguïtés, à t'assurer, si deux projets proposent une fonctionnalité qui -- manque de bol -- a été nommée de manière identique, de pouvoir choisir précisément la fonctionnalité que tu veux utiliser.

    Mais le fait est, justement, que moins d'ambiguité ne va pas forcément de paire avec plus de lisibilité... Bien au contraire.

    Regarde, par exemple, le projet boost! Il s'agit d'un projet "générique" qui regroupe ... 155 "sous projets" différents (à l'heure d'écrire ces lignes).

    Certains de ces projets sont surtout des ensembles de macros, et certains sont directement accessibles depuis l'espace de noms boost.

    Mais d'autres sont parfois accessibles depuis un espaces de noms spécifique qui se trouve dans l'espace de noms boost (un peu comme le contenu de la boite "jardinage", qui se trouve dans la boite "outils"), et certains de ces projets utilisent même des espaces de noms "imbriqués", ce qui fait qu'il est fréquent de devoir utiliser un code proche de boost::sous_projet::sub::fonctionnalité, dont le moins que l'on puisse dire, c'est que ca ne facilite pas forcément la lecture.

    Prenons l'exemple du tutorial de boost::filesystem dont le premier exemple que l'on rencontre utilise la directive using namespace boost::filesystem:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
    #include <boost/filesystem.hpp>
    using namespace boost::filesystem;
     
    int main(int argc, char* argv[])
    {
      if (argc < 2)
      {
        std::cout << "Usage: tut1 path\n";
        return 1;
      }
      std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
      return 0;
    }
    Et voici ce que cela donnerait sans la directive:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <iostream>
    #include <boost/filesystem.hpp>
     
    int main(int argc, char* argv[])
    {
      if (argc < 2)
      {
        std::cout << "Usage: tut1 path\n";
        return 1;
      }
      std::cout << argv[1] << " " << boost::filesystem::file_size(argv[1]) << '\n';
      return 0;
    }
    Non, définitivement, la première version me semble plus facile à lire... MAIS... elle brise le système d'espaces de noms, et c'est la deuxième version qui devrait donc être préférée
    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. Espace de noms, DLL, etc..
    Par Franck.H dans le forum VB.NET
    Réponses: 5
    Dernier message: 24/09/2013, 20h53
  2. chercher le nom dll
    Par specialhaha dans le forum C++
    Réponses: 6
    Dernier message: 23/01/2008, 13h04
  3. espace nom manquant
    Par Hepil dans le forum ASP.NET
    Réponses: 2
    Dernier message: 09/05/2007, 09h26
  4. Espace nom de champ - Table Paradox
    Par persam dans le forum Paradox
    Réponses: 4
    Dernier message: 23/04/2007, 13h09
  5. probleme d'espace nom
    Par Clara_G dans le forum C++
    Réponses: 1
    Dernier message: 04/04/2007, 09h07

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