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 :

Fonctionnement du Pré-Processeur


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 52
    Points : 55
    Points
    55
    Par défaut Fonctionnement du Pré-Processeur
    Bonjour, je suis désolé d'intervenir sur quelque chose d'aussi basique mais je ne comprend pas bien l'intérêt des inclusions sécurisées. En fait j'ai eu des problèmes de liens sur un programme et j'ai donc fais des essais sous Microsoft Visual C++ 6.0 qui m'ont amené les mêmes erreurs. Je m'explique : J'ai fais un header head.h et deux source files main.cpp et head.cpp qui incluent tous deux head.h. Voici simplement le head.h :

    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
    #ifndef TRUC_H
    #define TRUC_H
     
    class clacla
    {
    public:
    	float a;
     
    	clacla();
    	int truc();
    };
     
    int machin();
    extern int b;
    #endif
    J'ai implémenté clacla::clacla(), clacla::truc() et machin() dans head.cpp et pas de problèmes. Hors je retire simplement les commandes du préproceseur dans head.h, c'est à dire les #ifndef TRUC_H #define TRUC_H #endif, et cela continue de fonctioner. Apperement j'ai lu que l'on pouvait déclarer deux fois une variable à condition que le type corresponde exactement. Mais j'ai lu aussi que lorsqu'on écris int b; la variable est initialisé donc b est défini et il faut donc ecrire extern pour considéré qu'elle est seulement déclaré. Donc tout paraît normal. Mais si je rajoute la sécurité (#ifndef TRUC_H #define TRUC_H #endif) et que j'enlève le extern avant int b; cela ne fonctionne plus j'ai une erreur de lien :
    main.obj : error LNK2005: "int b" (?b@@3HA) already defined in head.obj
    Je ne peux donc rien définir dans mon head.h, il va s'en dire que je ne peux pas espérer initialiser b à 0 par exemple. Dois-je en conclure que ma sécurité c'est du vent???? Logiquement il me semble qu'il devrait zaper le second passage dans head.h car TRUC_H est sensé être déjà défini. Je ne comprend donc pas l'intérêt de la sécurité d'inclusion si on ne peut que décalrer et non définir des variables ou des fonctions vu que sans ça marche quand même dans ce cas. Quelqu'un peut il m'éclairer??? J'ai forcement fais une erreur ou tres mal compris un point! Merci d'avance!

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    1) C'est généralement pour les classes que la double-inclusion foire
    2) De quel droit tu implémentes des fonctions dans head.h ?

    PS: ton autre erreur, c'est une erreur au linkage. Une variable globale non-statique ne doit être définie que dans un seul fichier source. (et surtout pas dans un header).
    Par contre, elle peut être déclarée extern dans un header.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 52
    Points : 55
    Points
    55
    Par défaut
    Citation Envoyé par Médinoc
    2) De quel droit tu implémentes des fonctions dans head.h ?
    Oups, c'est une erreur je ne les ais pas implémentées dans le .h mais dans le .cpp, j'ai fais une faute (corrigée) en écrivant mon post, et non mon mini programme d'essai. Désolé!!!! Mais bon il faut pas le prendre sur ce ton, j'ai le droit de faire des erreurs, sinon j'aurais pas de quéstions à poser!
    Donc c'est pour les classes que ça foire. Je suppose que c'est valable pour les namespaces les structs les enums et les template?

    Citation Envoyé par Médinoc
    PS: ton autre erreur, c'est une erreur au linkage. Une variable globale non-statique ne doit être définie que dans un seul fichier source. (et surtout pas dans un header).
    Par contre, elle peut être déclarée extern dans un header.
    Je te remercie mais il y a quelquechose qui me gène. Pourquoi dans ce cas quand je n'inclus qu'une fois mon fichier "head.h", genre que dans "head.cpp" ou que dans"main.cpp" (en prennant dans ce cas soin de mettre en commentaire l'implémetation de "head.cpp") il n'y a pas d'erreur de linkage même si je ne mets plus extern int b; mais int b; ou int b=0; ? J'en viens à penser que j'ai donc le droit de définir une variable globale non statique dans un header mais qu'une seule fois??? Et c'est là que je comprend mal le fonctionnement du #ifndef parceque si j'ai le droit de le faire une fois et pas deux c'est qu'il zape mon #ifndef? Je veux pas être lourd mais ça m'échappe un peu.

    PS : ne prends pas mal la bizzarie du sujet de ce post, j'aurais pu me debrouiller sans poser ma quéstion et en définissant mes variables une fois dans un des .cpp approprié et parfois en les déclarants avec extern mais j'avais juste peur de faire du code à l'aveuglette. Je veux dire de ne pas comprendre vraiment pourquoi je le fais.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    En fait, le #ifdef ne sert pas aux variables, mais surtout aux classes (pour le reste, sais pas trop, pas vraiment essayé).

    Pour le coup des variables globales non-statiques, les gardes d'inclusion (#ifdef et compagnie) ne servent absolument à rien puisque le .h est inlcus au moins une fois dans chaque source qui l'inclut.

    Et si le .h est inclut dans deux sources et que la variable globale non statique y est définie et non déclarée, tu te retrouves avec la même variable définie deux fois dans le projet: Résultat, ça plante à l'édition de liens...
    (Enfin, peut-être pas avec GCC, mais je ne crois pas que d'après la norme, ce soit supposé marcher).

    En fait, là même chose se passe si tu définis une fonction non-statique dans deux sources: Tu en a une en trop, et l'éditeur de liens ne sait pas laquelle choisir...


    Conclusion, on ne définit jamais de variable globale non-statique dans un header, tout comme on n'y définit jamais de fonction non-statique...
    Et limite, on ne devrait même pas y définir de variable globale statique...
    (En fait, il est plutôt conseillé de ne définir aucune fonction réelle dans un header, c'est-à-dire aucune fonction qui ne soit ni inline ni template... La convention, c'est que le header ne doit générer aucun code: =~= Il doit contenir "des déclarations et aucune définition")
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Décembre 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Décembre 2005
    Messages : 109
    Points : 161
    Points
    161
    Par défaut
    Quelques intérêts des inclusions sécurisées :
    - Eviter d'avoir plusieurs définitions pour les fonctions et variables statiques définies dans un header (je ne parle pas ici des propriétés et méthodes statiques d'une classe)
    - Eviter une boucle dans les inclusions : si foo.hpp inclue bar.hpp et bar.hpp inclue foo.hpp


    Et pour mieux comprendre le fonctionnement du préprocesseur, avec gcc/g++ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    g++ -E main.cpp -o main.e
    g++ -E head.cpp -o head.e
     
    g++ -S -xc++ main.e -o main.s
    g++ -S -xc++ head.e -o main.s
     
    g++ -c main.s -o main.o
    g++ -c head.s -o head.o
     
    g++ main.o head.o -o a.bin
    # ou a.exe sous windows

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 52
    Points : 55
    Points
    55
    Par défaut
    Ok je crois que je comprend! Merci bien! Je vais mettre les variables de mes .h à l'interieur de mes classes du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #ifndef TRUC_H
    #define TRUC_H
     
    class clacla
    {
    public:
    	static unsigned int Number;
    	clacla();
    	unsigned int New();
    };
     
    #endif
    et implémenter dans mon .cpp :

    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
    #include "head.h"
     
    unsigned int clacla::Number=0;
     
    clacla::clacla()
    {
    	Number=New();
    }
     
    unsigned int clacla::New()
    {
    	static unsigned int n=0;
    	n=n+1;
    	return n;
    }
    Ainsi je n'aurais plus de variables qui se promenerons dans mes .h ...
    Je suppose que c'est le genre de chose qu'il faut faire? J'espère que c'est rigoureux.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 52
    Points : 55
    Points
    55
    Par défaut
    Et pour mieux comprendre le fonctionnement du préprocesseur, avec gcc/g++ :
    Euh pardon mais je suis largué je ne sias pas ce que c'est que gcc/g++ en fait... C'est un compilateur free gcc non? J'utilise Visual C++ ...

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    ce qu'il montrait en fait, ce sont les options "sortie du préprocesseur" et "listing assembleur" de GCC...

    Le compilo de Visual possède des options similaires, mais on ne peut pas les mettre simplement avec les options du projet dans Visual 6 (Il faut les rajouter sur la ligne de commande, et elles ne s'appellent pas pareil).

    Mais si tu as VS 2005, tu les as directement dans les options du projet (pour les versions intermédiaires, je ne sais pas)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre habitué
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Décembre 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Décembre 2005
    Messages : 109
    Points : 161
    Points
    161
    Par défaut
    Citation Envoyé par Coelacanthe
    Et pour mieux comprendre le fonctionnement du préprocesseur, avec gcc/g++ :
    Euh pardon mais je suis largué je ne sias pas ce que c'est que gcc/g++ en fait... C'est un compilateur free gcc non? J'utilise Visual C++ ...
    Oui. C'est le compilateur utilisé par défaut sous linux. Pour le trouver sous windows, cherche mingw.
    Puisque tu travail sous Visual C++, ne prend pas en compte mon passage qui parle de gcc



    Pour revenir à ton message précédent et au problème : utiliser un extern int b ou une variable statique dans une classe, c'est qu'une question de goût et de philosophie. Le second est sans doute plus orienté programmation objet cependant ...

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 52
    Points : 55
    Points
    55
    Par défaut
    Ok merci je vais me renseigner à propos des fonctions similaire sur Visual c++ 6!!

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Sortie du préprocesseur sous Visual (Sous VC++ 6, le fichier ne sera pas compilé, comme sous GCC):
    • Avec numéros de ligne, vers un fichier: /P
    • Sans numéros de ligne, vers la sortie standard: /EP
    • Avec numéros de ligne, vers la sortie standard: /E
    • Pour garder les commentaires dans le fichier en sortie, rajouter l'option /C


    Listing assembleur:
    • Assembleur seulement: /FA
    • Assembleur, code machine et source: /FAcs
    • Assembleur et code machine: /FAc
    • Assembleur et code source: /FAs


    Je recommande /P /C pour voir la sortie du préprocesseur, /FAs pour voir le code assembleur généré par le compilateur.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 16/08/2010, 15h52
  2. Fonctionnement des processeurs
    Par PapyJohn dans le forum Assembleur
    Réponses: 8
    Dernier message: 23/11/2007, 09h35
  3. [Turbo Pascal] TP7 fonctionne en QWERTY
    Par callahan dans le forum Turbo Pascal
    Réponses: 9
    Dernier message: 08/02/2003, 21h49
  4. Processeur
    Par delire8 dans le forum C++Builder
    Réponses: 14
    Dernier message: 05/09/2002, 13h33
  5. swapping entre processeurs
    Par shef dans le forum MFC
    Réponses: 5
    Dernier message: 26/08/2002, 14h20

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