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 :

Variables globales et compilation séparée.


Sujet :

C

  1. #1
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut Variables globales et compilation séparée.
    Salut!
    Je viens de finir un programme qui marche normalement, mais j'ai voulu le découper en plusieurs fichiers et depuis il ne compile plus. Il me signale des définitions multiples mais l'erreur provient des fichiers du répertoire /tmp.
    Après quelques recherches j'ai vu qu'il faut utiliser extern avant de déclarer les variables mais je ne comprends pas vraiment et ça ne marche toujours pas!
    Pour le moment, les variables globales sont déclarées dans le header et le header est inclus dans tous les fichiers.
    Merci d'avance pour vos réponses.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 064
    Points
    219 064
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Pour un projet utilisant plusieurs fichiers de compilations, il est important que les fichiers d'entêtes (.h) contiennent les gardes, c'est à dire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #ifndef FICHIER_H
    #define FICHIER_H
     
    // Les déclarations des fonctions
     
    #endif
    Maintenant, les variables. En fait, vous ne devriez pas avoir de variable globales (disons qu'il y a que très peu de chances que cela vous soit totalement nécessaires). Donc le plus simple serait de les éviter et de prendre de bonnes habitudes tout de suite.
    Pour revenir au mot clé extern, vous pouvez lire la FAQ C.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 373
    Points : 23 629
    Points
    23 629
    Par défaut
    Bonsoir,

    Si tu ne nous présentes ni ton code, ni le message d'erreur, ça va être difficile d'être précis.

    Citation Envoyé par dré kam Voir le message
    Je viens de finir un programme qui marche normalement, mais j'ai voulu le découper en plusieurs fichiers et depuis il ne compile plus. Il me signale des définitions multiples mais l'erreur provient des fichiers du répertoire /tmp.
    Si tu vois des fichiers aux noms bizarres dans /tmp, c'est que c'est en fait le linker qui est à l'œuvre. Ça veut dire que tes fichiers compilent tous correctement individuellement, mais qu'il est impossible de les rassembler pour former l'exécutable final. Sans doute, ici, à cause de conflits.

    Après quelques recherches j'ai vu qu'il faut utiliser extern avant de déclarer les variables mais je ne comprends pas vraiment et ça ne marche toujours pas! Pour le moment, les variables globales sont déclarées dans le header et le header est inclus dans tous les fichiers. Merci d'avance pour vos réponses.
    1. Les variables globales, c'est mal ;
    2. Sache que le compilateur C ne fait pas le distingo lui-même entre les différents types de fichiers source (*.h, *.c, etc.). Si tu inclus un fichier à un endroit donné, ce sera comme si tu avais saisi son contenu directement à cet endroit.


    « extern » permet justement de dire au compilo qu'une variable existe bien mais ailleurs. Il te croira sur parole et la résolution de son adresse en mémoire sera faite à l'édition des liens. Donc, si tu as déclaré une variable globale dans un header, elle sera retrouvera instanciée dans chacun des fichiers qui l'incluent. Et, à l'édition des liens, on va se retrouver avec n variables en conflit portant toutes le même nom.

    Si maintenant , tu mets « extern » partout, cela va compiler mais, au bout d'un moment, il faudra bien la créer pour de vrai, cette variable. Sinon, là encore à l'édition des liens, le linker va te dire que tu y fais référence mais qu'il ne la trouve pas.

    Ce qu'il faut faire, donc, c'est la déclarer « extern » dans ton header pour que tous les fichiers puissent s'y référer, puis l'instancier dans un et un seul code *.c .

  4. #4
    Membre éclairé
    Avatar de bpy1401
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2003
    Messages
    471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2003
    Messages : 471
    Points : 831
    Points
    831
    Par défaut
    Bonjour

    Voici un petit exemple qui recapitule tout cela

    fichier1.c qui produit toto

    fichier1.h qui déclare toto pour les autres

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #ifndef FICHIER_1
    #define FICHIER_1
     
    extern int toto;
     
    #endif
    fichier2.c qui utilise toto

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include "fichier1.h
     
    void fonction(void)
    {
       toto = 5;
    }
    Page sur Developpez : http://pbriand.developpez.com

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Merci beaucoup, ça marche nickel.
    Cela dit je sais que c'est pas conseillé les variables globales mais là ça rend le code beaucoup plus présentable; je dois réécrire ls donc je trouve que c'est bien plus joli de mettre les options en global que de passer autant d'arguments que d'options possibles à chaque fonction.

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 373
    Points : 23 629
    Points
    23 629
    Par défaut
    Bonjour,

    Citation Envoyé par dré kam Voir le message
    Cela dit je sais que c'est pas conseillé les variables globales mais là ça rend le code beaucoup plus présentable; je dois réécrire ls donc je trouve que c'est bien plus joli de mettre les options en global que de passer autant d'arguments que d'options possibles à chaque fonction.
    Tu te trompes. Il faut que tu relises mon post car, si c'est un exercice scolaire, ton prof risque d'être assez mécontent, et ce sera à juste titre. L'objectif de l'exercice est justement de prendre d'emblée les bonnes habitudes et de ne pas céder à cette facilité.

    Pour réécrire ls, tu n'as besoin que de deux fonctions : la fonction main() qui fait les inits, ressort avec le bon code d'erreur, parse éventuellement les options et ta fonction de parcours du répertoire. À aucun moment, tu n'as besoin de variables globales pour gérer tout cela, et encore moins pour passer des valeurs d'une fonction à l'autre.

    Si tu ne fais que lister à plat le contenu d'un répertoire, ta fonction est purement itérative et la seule chose que tu aies besoin de lui passer est le nom du répertoire à explorer. Mieux, tu ouvres le répertoire avec opendir() depuis main(), et tu passe la ressource ouverte à l'autre fonction. Donc, un seul argument.

    Si tu veux ensuite simuler le comportement de « ls -R », qui ré-entre automatiquement dans les sous-répertoires quand il en trouve, c'est à peine plus difficile : ta fonction devient récursive. Il s'agit simplement d'ouvrir à nouveau le sous-répertoire rencontré et de se rappeler soi-même en passant en paramètre le pointeur vers la structure DIR renvoyée par opendir(), exactement de la même façon que main() l'a fait pour le premier.

    Mais là, pour le coup, tes variables doivent impérativement se trouver dans la pile et NE DOIVENT PAS être globales, sinon ça ne marchera pas. Et je pense que c'est ce que ton prof veut que tu fasses.

    Donc oublie les globales dans ce cas précis, parce que même la facilité d'utilisation n'est plus justifiée.

  7. #7
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    J'ai fait plusieurs options, dont le -R mais aussi le -l et le -d etc... (j'en ai fait 6 en tout). Tout marche normalement. Mais j'ai fait une fonction d'affichage qui doit avoir accès à tous les paramètres, et 2 fonctions de tris (par date, par nom). Donc la fonction d'affichage doit savoir si il y a l'option -l ou -d etc.... pour savoir ce qu'elle doit afficher. En gros elle doit avoir autant d'arguments que d'options possibles et il en va de même pour d'autres fonctions. C'est pour ça que j'utilise les globales.
    Ceci dit est-ce que ce serait mieux de passer 8 valeurs en paramètres?

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 373
    Points : 23 629
    Points
    23 629
    Par défaut
    Citation Envoyé par dré kam Voir le message
    Ceci dit est-ce que ce serait mieux de passer 8 valeurs en paramètres?
    Ni l'un ni l'autre. Si tu te retrouves à passer huit valeurs en paramètre, c'est que ton modèle est bancal. Lorsqu'on a vraiment besoin de passer un contexte entier à plusieurs fonctions similaires, on utilise une structure qui contient toutes les informations nécessaires et on passe un pointeur pointeur vers cette structure à ces fonctions. Donc, un seul paramètre, et ça te permet éventuellement d'utiliser plusieurs contextes, le cas échéant. Cela dit, ce n'est pas cette approche que tu dois utiliser non plus.

    Si tu tries tes entrées de fichiers avant de ré-entrer dans tes sous-répertoires, ça t'empêche d'appliquer directement la récursivité mais, quelque part, c'est encore mieux parce que ça t'oblige à lire tout le contenu d'un répertoire avant de passer au suivant, ce qui te permet de ne garder qu'une seule structure DIR ouverte à la fois, et le système t'en sera reconnaissant.

    Mais là encore, que ce soit pour trier ou pour afficher, à aucun moment tu n'as besoin d'une fonction à huit paramètres.

    L'idée est d'en faire le maximum pendant la boucle qui te sert à parcourir les entrées du répertoire. En théorie, tu pourrais un tri insertion, par exemple, mais le plus facile au début reste le chargement d'un tableau de structures et son tri avec qsort().

    De là, chaque fonction ne doit recevoir en paramètre que les arguments dont elle a besoin pour faire son propre travail. Ta fonction « affichage », par exemple, n'a besoin de recevoir qu'un pointeur vers UNE SEULE structure « dirent » pour en afficher nom de son fichier à l'écran, et son type.

  9. #9
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Ni l'un ni l'autre. Si tu te retrouves à passer huit valeurs en paramètre, c'est que ton modèle est bancal. Lorsqu'on a vraiment besoin de passer un contexte entier à plusieurs fonctions similaires, on utilise une structure qui contient toutes les informations nécessaires et on passe un pointeur pointeur vers cette structure à ces fonctions. Donc, un seul paramètre, et ça te permet éventuellement d'utiliser plusieurs contextes, le cas échéant. Cela dit, ce n'est pas cette approche que tu dois utiliser non plus.
    Je trouve que ce serait très bien une structure "options" passée en paramètre. Pourquoi je ne devrais pas l'utiliser dans ce cas?

  10. #10
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 373
    Points : 23 629
    Points
    23 629
    Par défaut
    Citation Envoyé par dré kam Voir le message
    Je trouve que ce serait très bien une structure "options" passée en paramètre. Pourquoi je ne devrais pas l'utiliser dans ce cas?
    Parce que c'est le principe même de contexte global qui pose problème : il n'y a rien dans ton projet qui nécessite une telle approche et si tu te retrouves contraint d'y recourir, c'est qu'il y a quelque chose de mal conçu en amont.

  11. #11
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    D'accord je vais tenter d'améliorer l'algorithme. Merci pour votre aide!

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

Discussions similaires

  1. Variables globales pour compilation séparée
    Par latitude38 dans le forum Débuter
    Réponses: 9
    Dernier message: 08/12/2014, 12h31
  2. variable globale de type non prédéfini à la compilation
    Par Discovery dans le forum Débuter
    Réponses: 8
    Dernier message: 01/04/2009, 19h05
  3. Variable "globale" (dans plusieurs templa
    Par mattmat dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 17/06/2003, 19h22
  4. question sur les variables globales et les thread posix
    Par souris_sonic dans le forum POSIX
    Réponses: 5
    Dernier message: 13/06/2003, 13h59
  5. les variables globales static
    Par gRRosminet dans le forum C
    Réponses: 8
    Dernier message: 27/04/2002, 08h34

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