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

Autres éditeurs Discussion :

[VC++ vs gcc]Comportement compilateur et références croisée


Sujet :

Autres éditeurs

  1. #1
    Membre habitué Avatar de vdemeester
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    110
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 110
    Points : 125
    Points
    125
    Par défaut [VC++ vs gcc]Comportement compilateur et références croisée
    Bonjour,

    je fais actuellement un portage d'un application codée et développée avec Visual Studio 6. Le projet en lui-même est assez conséquent, mais il fonctionne et compile bien. Le portage se fait de windows vers Linux. Il faut donc changer d'outils (Makefile/autotools), et de compilateur (gcc).

    J'en suis actuellement à la seconde phase (après avoir convertit les .dep, .mak & co en des fichiers utilisables par les GNU autotools [automake, autconf, ..]) qui consiste au passage du compilateur de Visual Studio 6 à Gcc. Dans un premier temps, comme certaines parties du code dépendent de librairies windows (comme winsock), j'utilise mingw (le port de GCC sous windows). J'ai déjà corrigé pas mal d'erreurs (les __int64 de VS par exemple, etc..), mais je suis tombé sur un os, et j'ai peur de ne pas comprendre le comportement du compilateur de Visual Studio (et/ou inversement).

    Je me trouve dans un cas de références croisées. Je ne sais pas si c'est réellement le terme, alors je vais tenter une petite explication :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    hdr1.h
    class X1 a besoin de Y2 et Y3 (des champs Y3.bibi et Y2.bobo par exemple)
    class X2
     
    hdr2.h
    class Y1 a besoin de X1 et Z2
    class Y2 a besoin de X2
    class Y3 a besoin de Z1
     
    hdr3.h
    class Z1 a besoin de Y2 et X2
    class Z2
    Du coup, il faut que chacune inclue les 2 autres. J'ai bien le header define pour éviter que le compilateur ne tourne en rond dans la lecteur des .h. J'ai également bien déclaré des placeholder (c'est surement pas comme ça que ça s'appel non plus) comme par exemple pour ma librairie hdr1

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #ifndef _HDR1_H
    #define _HDR1_H
    #include "hdr2.h";
    #include "hdr3.h"
     
    class Y1;
    class Y2;
    class Y3;
    class Z1;
    class Z2;
     
    class X1 {
    [....] // le reste de mon code
    }
    [...]
    #endif
    Dans un cas simple cela marche, en compilant avec gcc (enfin g++) et le compilateur de Visual Studio.

    Maintenant, dans le code que j'ai à porter (qui n'est donc pas de moi au départ), il y a des éléments de code dans le header. Par exemple, il y a le code d'une des méthodes (un return Y2.LeChamp. Je n'ai pas pour habitude de mettre du code dans un header, mais j'ai cru comprendre que les codes inline (notion qu'il faut que j'approfondisse) était "obligatoire" dans le header. Mais pour revenir à mon problème, je fais donc appel à des champs 'une des classes, mais qui n'existe pas encore au moment ou le compilateur passe sur ce code [j'entends par là, qu'on lui a dit que Y2 était une classe, mais il n'a pas encore lu hdr2.h, par exemple]. Une solution serait bien entendu de virer tout code du header et le reporter dans les .cpp correspondant. C'est la "solution" que j'envisage.

    Cependant, je me pose une question. Ce code compile avec Visual Studio, et je continue de me manger de belles erreurs avec g++. Le compilateur de Visual Studio ne fonctionne pas de la même manière que g++, je m'en suis aperçu, mais je me demande jusqu'où ? Le compilateur de Visual Studio serait-il trop permissif (laissant passé des champs qui n'ont pas encore été définis) ou alors ferait-il plusieurs passes ?

    Si quelqu'un est capable de m'éclairer sur ce point, j'en serais ravi.

    Hum, ça avait plus sa place dans le forum "Outils pour C & C++ / EDI / Compilateurs / etc "
    Linux/Unix, Emacs and Free Software are evil
    GNU/Linux & FreeBSD powered user.

  2. #2
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Je vais tirer des plans sur la comète, vu que tu ne nous a pas donné toutes les informations (message d'erreur, ...).

    La notion de "header" est une notion de programmeur (et de préprocesseur), et non de compilateur.
    Une compilateur lit (et compile) un fichier unique.
    Le préprocesseur crée ce fichier unique en incluant d'autres fichiers (#include), et en créant du code (#define) ou en en supprimant/modifiant (#if ..)

    Je n'ai encore pas vu de cas ou la "compilation" soit intraséquement différente entre g++ et visual, mais bon, je suis pas un pro de g++. En tout cas avoir du code qui fait "return a.x;" sans avoir défini a crée une erreur dans visual normalement !

    Pour ce qui est des références "croisées" (A utilise B qui utilise A) c'est tout à fait accéptable.
    Par contre je suis pas sur du "à besoin de". Quelle relation est-ce ? Utilisation de la définition ? Pointeur (ou référence) ?

    Et pour en revenir à ton exemple, il tend bien à prouver que le paradygm Java (une classe / un header) est encore le meilleur à suivre en C++:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    X1.h: class X1 utilise Y2 et Y3  (inclus Y2.h,Y3.h)
    X2.h: class X2
    Y1.h: class Y1 utilise X1 et Z2  (inclus X1.h,Z2.h)
    Y2.h: class Y2 utilise X2          (inclus X2.h)
    Y3.h: class Y3 utilise Z1          (inclus Z1.h)
    Z1.h: class Z1 utilise Y2 et X2  (inclus Y2.h, X2.h)
    Z2.h: class Z2
    En déroulant les includes on a aucune référence croisée:
    X1.h: inclus Y2.h,X2.h,Y3.h,Z1.h,[Y2.h],[X2.h],[X2.h]
    X2.h: inclus rien
    Y1.h: inclus X1.h,Y2.h,X2.h,Y3.h,Z1.h,[Y2.h],[X2.h],[X2.h]
    Y2.h: inclus X2.h
    Y3.h: inclus Z1.h,Y2.h,X2.h,[X2.h]
    Z1.h: inclus Y2.h,X2.h,[X2.h]
    Z2.h: inclus rien
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  3. #3
    Membre habitué Avatar de vdemeester
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    110
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 110
    Points : 125
    Points
    125
    Par défaut
    Hum, mon exemple n'étais pas bon alors. Toujous est-il que dans le "réel", j'ai 3 header qui s'incluent mutuellement. Dans mon exemple j'aurais mieux faire d'écrire donc ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    X1.h: class X1 utilise Y1, Y2 et Y3  (inclus Y1.h, Y2.h,Y3.h)
    X2.h: class X2
    Y1.h: class Y1 utilise X1 et Z2  (inclus X1.h,Z2.h)
    Y2.h: class Y2 utilise X2          (inclus X2.h)
    Y3.h: class Y3 utilise Z1          (inclus Z1.h)
    Z1.h: class Z1 utilise Y2 et X2  (inclus Y2.h, X2.h)
    Z2.h: class Z2
    La, on se retrouve bien avec un référence croisée, n'est-ce pas ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    X1.h: inclus Y1.h,Y2.h,X2.h,Y3.h,Z1.h,X1.h,[Y2.h],[X2.h],[X2.h]
    X2.h: inclus rien
    Y1.h: inclus X1.h,Y2.h,X2.h,Y3.h,Z1.h,Y1.h,[Y2.h],[X2.h],[X2.h]
    {...}
    On va y aller par palier. Imaginons que je suis dans le cas de références croisées. Le préprocesseur lit le premier header (X1.h par exemple), il voit les #include vers Y1, Y2 et Y3. Il commence dans l'ordre, Y1 par exemple. La, il voit un #include vers X1. Si j'ai bien compris, il ne va pas relire X1.h, puisqu'il l'a déjà lu en partie (jusqu'à l'include de Y1.h) et que donc _X1_H est définit (le test permettant de ne pas relire 10 fois un .h). Dans Y1, on a bien précisé, juste après les #include, qu'il existait une classe X1 (dans X1.h) en lui donnant juste class X1. Normalement, si tout se passe bien (et que l'on ne fait pas appel à un champs de la classe X1 [qui est à ce moment précis encore indéfini, puisque le préprocesseur n'a pas encore finis de lire X1 et ainsi tous les champs et autres déclarations de X1), il finit de lire Y1.h (admettons qu'il a parcouru tous les autre #include sans soucis). Il revient alors sur X1.h et finit "sa lecture" de ce fichier.

    A quelques chose près, c'est comme ça que ça se passe, non ?

    Le principal soucis que j'ai, c'est que dans Y1.h, il est fait utilisation d'un champs de la classe X1. A priori, je n'ai pas d'autre choix que, soit de déporter tout code faisant utilisation de champs de X1 dans la source .cpp correspondante, soit faire une sorte de "header" général pour les deux, non ?
    Linux/Unix, Emacs and Free Software are evil
    GNU/Linux & FreeBSD powered user.

  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,

    D'abord, il faudrait t'assurer qu'il soit vraiment nécessaire d'avoir l'implémentation des méthodes dans les fichiers d'en-tête, et principalement en ce qui concerne
    • les méthodes de X1 faisant appel à Y2 et/ou Y3
    • les méthodes de Y1 faisant appel à X1 et/ou Z2
    • les méthodes de Y2 faisant appel à X2
    • les méthodes de Y3 faisant appel à Z1
    • les méthodes de Z1 faisant appel à Y2 et/ou X2

    En effet, il n'y a réellement que dans le cas de classe modèles (template) que l'implémentation doive, d'une manière ou d'une autre, se retrouver dans le fichier d'en-tête

    Pour ce qui est de l'inlining éventuel de fonction, je t'inviterais peut être à réfléchir à la nécessité réelle de l'utilisation pour les méthodes citées précédemment... Pour te faire une idée, tu peux te baser sur un débat qui date d'il y a quelques semaines:=>Pourquoi pas inline systématiquement<=

    Cette (longue) introduction était rendue nécessaire par le peu d'informations que tu avais données en ce qui concerne les différentes classes

    Pour résoudre le problème une fois que tu as "retiré" des fichiers d'en-tête qui n'ont rien à y faire, il suffira de te baser sur l'entrée de la FAQ qui parle des =>références croisées<=

    L'idée de base étant d'effectuer une déclaration anticipée des classes dont tu as besoin dans les fichier d'en-tête et d'inclure les fichiers d'en-têtes dans lesquelles ces classes sont réellement déclarées dans les fichiers dans lesquels une (ou plusieurs) fonctions ont besoin de savoir précisément ce qui constitue ces classes
    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 habitué Avatar de vdemeester
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    110
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 110
    Points : 125
    Points
    125
    Par défaut
    Citation Envoyé par koala01
    Salut,

    D'abord, il faudrait t'assurer qu'il soit vraiment nécessaire d'avoir l'implémentation des méthodes dans les fichiers d'en-tête, et principalement en ce qui concerne
    • les méthodes de X1 faisant appel à Y2 et/ou Y3
    • les méthodes de Y1 faisant appel à X1 et/ou Z2
    • les méthodes de Y2 faisant appel à X2
    • les méthodes de Y3 faisant appel à Z1
    • les méthodes de Z1 faisant appel à Y2 et/ou X2

    En effet, il n'y a réellement que dans le cas de classe modèles (template) que l'implémentation doive, d'une manière ou d'une autre, se retrouver dans le fichier d'en-tête

    Pour ce qui est de l'inlining éventuel de fonction, je t'inviterais peut être à réfléchir à la nécessité réelle de l'utilisation pour les méthodes citées précédemment... Pour te faire une idée, tu peux te baser sur un débat qui date d'il y a quelques semaines:=>Pourquoi pas inline systématiquement<=

    Cette (longue) introduction était rendue nécessaire par le peu d'informations que tu avais données en ce qui concerne les différentes classes
    J'en suis bien conscient (pour l'implementation de méthode dans le header), le soucis étant que je fait le portage d'une application développée durant les 3 dernières années, par d'autres personnes que moi, c'est ce que j'ai constaté.

    Citation Envoyé par koala01
    Pour résoudre le problème une fois que tu as "retiré" des fichiers d'en-tête qui n'ont rien à y faire, il suffira de te baser sur l'entrée de la FAQ qui parle des =>références croisées<=

    L'idée de base étant d'effectuer une déclaration anticipée des classes dont tu as besoin dans les fichier d'en-tête et d'inclure les fichiers d'en-têtes dans lesquelles ces classes sont réellement déclarées dans les fichiers dans lesquels une (ou plusieurs) fonctions ont besoin de savoir précisément ce qui constitue ces classes
    Je connais également cette solution, j'ai déjà eu à faire à des références croisée, et j'ai employé cette méthode, mais j'avais surtout envie de savoir/comprendre s'il y avait une "si grande" différence que ça dans le processus de compilation de vc++ et de g++.

    (Je m'en vais réécrire ces headers (et le sources associées) et on verra comment ça se passe).
    Linux/Unix, Emacs and Free Software are evil
    GNU/Linux & FreeBSD powered user.

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

Discussions similaires

  1. Problème de référence croisée
    Par Nyphel dans le forum C++
    Réponses: 10
    Dernier message: 18/04/2007, 14h23
  2. Réponses: 5
    Dernier message: 21/03/2007, 13h24
  3. [Débutant] Références croisées entre packages
    Par dabeuliou dans le forum Langage
    Réponses: 6
    Dernier message: 05/03/2007, 13h30
  4. effacer des références croisées
    Par jan0 dans le forum Oracle
    Réponses: 3
    Dernier message: 12/10/2006, 11h09
  5. Références croisées d'objets Oracle
    Par cdemedei dans le forum Oracle
    Réponses: 2
    Dernier message: 23/02/2006, 16h33

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