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 :

Langage C, variables globales


Sujet :

C

  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Par défaut Langage C, variables globales
    Bonjour. Je voudrai utiliser des variables globales, et je voudrai savoir si il est possible
    de les initialiser dans le fichier global.c tel que décrit à cet endroit dans la FAQ C. Merci beaucoup.

    http://c.developpez.com/faq/c/?page=...TYPES_globales

    Je voudrai aussi savoir si l'utilisation de variables globales permet leur
    modification par valeur de façon certaine, (et non de façon vaine comme
    l'échange de valeurs dans un tableau en passant les arguments par valeur au
    lieu de les passer par référence) .

    Par exemple, plus concrètement, est ce que ce programme est cohérent ?



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    extern int  jour = 1;
     
    void change_jour(int k)
      {
      k=k+1;
      }
     
    void main(void)
      {
      change_jour(jour);
      printf("le jour modifié est 2 et plus 1, comme je l'esperais : %d\n", jour);
      }

    (Je sais que le langage C ne se manipule pas de façon évidente, j'ai peur de faire une bêtise)

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Salut,

    Du fait qu'une variable globale n'est jamais qu'une variable qui est connue par l'ensemble des fonctions, tu peux la modifier exactement comme n'importe quelle autre variable, dans la limite de sa déclaration...

    Pour expliquer plus clairement ma réponse, je vais prendre quelque cas précis:
    1. la variable est un entier non constant
    2. la variable est un entier constant
    3. la variable est une chaine (tableau de caractère) non constante
    4. la varaible est une chaine constante

    En [1], tu pourras appliquer toute les opérations mathématiques, et les tests classiques:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    mavar++;
    mavar*=3;
    mavar/=2; /* il faut juste penser au problème de la division de deux entiers */
    mavar-=36;
    if(mavar>3)
        /*...*/
    if(mavar>=6)
       /*...*/
    if(mavar==19)
        /*...*/
    if(mavar!=13)
        /*...*/
    En [2] tu pourras effectuer les tests arithmétiques classiques, mais tu ne pourras pas modifier la valeur, du fait de la constance de la variable (et uniquement de ce fait )

    En [3] tu pourras modifier/tester la valeur de la chaine en utilisant les fonctions de modification/test de la valeur de chaine:strcmp, strcpy, strdup...

    Mais cela tiens plus au fait que la variable "chaine" indique en réalité l'adresse à laquelle se trouve le premier élément du tableau qu'à autre chose

    En [4] enfin, la constance de la variable empeche la modification de la valeur, mais autorise le test à coup de strcmp...

    La seule chose à laquelle il faille etre attentif, c'est d'etre sur que les fonctions qui modifieront/testeront la valeur de la variable globale disposent, de par leur jeu d'inclusion d'entete, de la déclaration de la variable

    C'est à dire que, si elle est déclarée dans fichier1.h, il faut l'instruction preprocesseur #include "fichier1.h" ou qu'il faut inclure un fichier d'entete qui inclue (un fichier qui inclue, un fichier qui inclue) fichier1.h
    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

  3. #3
    Membre éclairé
    Avatar de JMLLB
    Inscrit en
    Septembre 2006
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 285
    Par défaut
    Citation Envoyé par kromartien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void change_jour(int k)
      {
      k=k+1;
      }
    Ta fonction ne va pas faire grand chose, le problème ne vient pas des variables globales, mais du passage de paramètre.
    Jettes un oeil:
    http://c.developpez.com/cours/bernar...gne/node46.php

  4. #4
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    comme on l'a dit plusieurs problèmes :

    • comme dit juste au dessus, le fait de passer "int k" en argument est inutile si c'est une variable globale, et d'autre part dans ce cas précis fera un mic-mac étrange.


      • Soit tu fais une fonction locale, qui prend un "int *" et dont tu modifieras l'argument dans la fonction.
      • Soit tu te sers de la variable globale, et tu n'as pas besoin de passer en argument.


    • Ensuite, tu déclares une variable gloabe en extern (ce qui veut dire qu'elle est définie ailleurs), et tu l'initialises, ce qui est pas franchement logique. Et si en plus, comme c'est le cas dans ce que tu montres, il n'y a pas d'include, où est-elle définie ??


    Admettons que ce soit dans ton programme principal que tu la déclares. tu fais alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int  jour = 1 ;
     
    int main ( void )
    {
    .....
    }
    et dans un autre fichier .c tu pourras déclarer :

    et dans cet autre fichier, tu auras accès à la variable, et tu pourras la modifier.

  5. #5
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Par défaut
    Merci beaucoup pour vos réponses. Je vous ai lu attentivement.

    Ma fonction a les spécifications suivante :
    Elle utilise la valeur initiale de k
    (qui est toujours une variable global, mais je ne pense pas que écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void change_jour(extern int * k)
    se fasse)
    , puis elle l'incrémente en fin de traitement, seulement lorsque les opérations préalables basées sur la valeur de k ont été réalisées.
    (test conditionnel peut être utile pour ne pas sauter une opération ?)

    Ainsi, il y a bien une utilisation en lecture qui est faite de k avant l'incrémentation, ce qui justifie le fait que de toutes les manières, la fonction a accès à la valeur de k, que ce soit par référence ou directement par valeur.

    Maintenant, vous me dites que c'est du mic-mac pour le C. Je devrai donc définir ma fonction de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    extern int  jour = 1;
     
    void change_jour(int * k)
      {
      printf("voilà le jour du debut : %d\n",*k);
      (*k)=(*k)+1;
      }
     
    void main(void)
      {
      change_jour(&jour);
      printf("le jour modifié est 2 et plus 1, comme je l'esperais : %d\n", jour);
      }
    pour que ce soit cohérent du point de vue du C, car, ce que je retire de votre lecture est que de toutes les manières, le passage par référence des arguments est bien plus cohérent avec le fonctionnement du C, même s'il s'agit d'une variable globale déclarée avec le mot clé extern.


    __De l'utilisation au sein d'un même programme de variables globales__
    Pour les déclarations dans des fichiers externes et leur inclusion, j'ai construit un fichier en-tête 'global_header.h' inclut dans chaque fichier source du projet qui contient donc les déclarations des variables globales avec la syntaxe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    extern char mavariable1;
    extern char mavariable2;
    ...
    [EDIT : je voulais pas dire static mais bien extern/]
    J'intialise chacune de ces variables dans un fichier .c du projet, inclu à la compilation, construit comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #include "global_header.h"
     
    char mavariable1=0;
    char mavariable2=0;
    ...
    Je précise également que chaque fichier source (.c) du projet contient l'inclusion de l'en tête global_header.h.

    Je me suis inspiré pour cette construction de la question de la FAQ C donnée en lien dans mon premier post. Merci de me dire également si c'est correct.

    Merci beaucoup en tout cas pour vote patience.

  6. #6
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    oui mais c'est faux..

    Si tu déclares

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    static char MaVariable ;
    cela signifie qu'elle est LOCALE au module/fichier.

    Cela n'a donc aucun sens de la mettre dans un fichier "globale".

    En général, il faut éviter les variables globales. Déjà, c'est peu recommandé, et à la limite on peut avoir à s'en servir, mais globale à 1 fichier .c .

    Utiliser une variable globale à PLUSIEURS fichiers .c relève de la mauvaise conception. Il y a eu tout un thread sur ce forum il y a quelque temps là-dessus : à part quelques cas très particuliers (et encore contournables), cela est non seulement non nécessaire, mais TRES fortement découragé.

    [EDIT]

    D'ailleurs en suivant le lien, je tombre sur :

    globale.h
    globale.c
    fi1.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #include "globale.h"
     
    ...
    fi2.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #include "globale.h"
     
    ...
    ce qui ne correspond PAS DU TOUT à ta manière de faire.

    [/EDIT]

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    A partir du moment ou ton fichier d'implémentation (*.c) inclus, meme indirectement, la déclaration de ta variable globale, tu n'as purement et simplement plus besoin de la passer en parametre aux fonctions définies dans le fichier d'implémentation... elle sera connue d'office de toutes les fonctions, sous le nom que tu lui a donné...

    Ainsi, quand tu écris le code, dans globales.h:
    tu dis
    j'ai déclaré une variable globale de type integer(entier) nommée a dans un de mes fichiers d'implémentation...

    Cette variable globale doit etre utilisable par toutes les fonctions qui sont implémentée ailleurs
    tu trouveras, dans le fichier c dans lequel la variable est déclarée
    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
    17
     
    int a=0;
    void Add1ToA()
    {
       ++a;
    }
    void LessThan10()
    {
       if(a>10)
       {
           /*...*/
       }
       else
       {
           /*...*/
       }
    }
    et dans un autre fichier d'implémentation:
    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 "globales.h" /* grace à ca, le fichier connait l'existance de a */
     
    char* CreateString()
    {
     
        char *ret;
        if(a==0)
            perror("impossible d'allouer la memoire pour 0 caracteres");
        ret=malloc(a);/* alloue la mémoire nécessaire pour "a" char */
        if(ret==NULL)
            perror("erreur d'allocation");
       return ret;
    }
    Ceci dit, il est vrai que l'utilisation de variables globales n'est pas des plus recommandées...
    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

  8. #8
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Par défaut
    Une dernière question. Est-ce qu'il n'y a pas une forme de redondance dans le fait d'écrire :
    Citation Envoyé par global_header.h
    extern char i;
    puis
    Citation Envoyé par init_global.c
    #include global_header.h
    char i=0;
    au lieu de
    Citation Envoyé par global_header.h
    extern char i;
    puis
    Citation Envoyé par init_global.c
    #include global_header.h
    i=0;
    Je préfère utiliser des variables globales ici car j'ai l'impression que ça m'assure une gestion plus fine et moins redondante du code (pas de recopie multiples, etc).

    C'est un projet de microprogrammation. Je suis d'accord que les globales ne sont pas vraiment une bonne chose, mais je ne suis pas certain que employer des variables locales soit plus simple à l'exécution pour le processeur embarqué.

    Comme c'est du code embarqué, je ne sais pas trop ( :hesit). Tout passer par adresse peut aussi bien convenir, mais c'est avant tout pour ça que je préfère utiliser des variables globales à adresse fixe, qui sont manipulées par les fonctions les concernant.

    J'imagine qu'il faut prévoir un solide graphe d'interaction pour justifier ça. Merci en tout cas.

  9. #9
    Membre éclairé
    Avatar de JMLLB
    Inscrit en
    Septembre 2006
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 285
    Par défaut
    extern char i; => déclaration
    char i=0; => définition
    i=0; => utilisation

    Tu peux avoir autant de déclaration que tu veux, mais c'est lors de la définition qu'est créée la variable. A ce propos tu auras autant de variables que de définitions.

    Si tu fais ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //init_global.c
    #include global_header.h
    i=0;
    ta variable n'est pas créée ,en tout cas pas dans init_global.c.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //init_global.c
    #include global_header.h
    char i=0;
    Si tu n'as dans ton header que la déclaration de i ce n'est pas indispensable de l'inclure. Par contre c'est une structuration classique d'avoir un header et un body.

  10. #10
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par kromartien
    Bonjour. Je voudrai utiliser des variables globales,

    et je voudrai savoir si il est possible
    de les initialiser dans le fichier global.c tel que décrit à cet endroit dans la FAQ C.
    Ben oui, c'est même seulement là que c'est possible...

    http://emmanuel-delahaye.developpez....s.htm#globales
    Je voudrai aussi savoir si l'utilisation de variables globales permet leur
    modification par valeur de façon certaine, (et non de façon vaine comme
    l'échange de valeurs dans un tableau en passant les arguments par valeur au
    lieu de les passer par référence) .

    Par exemple, plus concrètement, est ce que ce programme est cohérent ?
    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
    extern int  jour = 1; 
    /* -ed- ceci n'a pas de sens. C'est la définition qui fixe la valeur 
              de démarrage, pas la déclaration.
    */
     
    void change_jour(int k)
      {
      k=k+1;
      }
     
    void main(void)
      {
      change_jour(jour);
      printf("le jour modifié est 2 et plus 1, comme je l'esperais : %d\n", jour);
      }
    Ben non, ça ne modifie rien du tout.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void change_jour(void)
      {
      jour++;
      }
    mais c'est grade (contraction de gravement crade). Pourquoi tu veux utiliser des globales ? C'est horrible. Est-ce justifé ?

  11. #11
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Par défaut
    En fait j'en parle plus haut dans le thread.

    C'est de la programmation embarquée, donc je pense que j'ai un code plus concis et que je maîtrise mieux avec des variables globales à adresse fixe lorsque je ne peux pas faire autrement.
    C'est ma première expérience dans ce domaine, je peux tout aussi bien me tromper.

    Je disais aussi, pour répondre au lien correspondant, que lorsque je rndrai mon rapport, il fauda que je prévois un graphe d'interaction entre les différentes fonctions, et les globales doivent être traitées avec tout le soin possible il est vrai.

    "L'instance étant unique, ça rend le code impropre à la récursion et à l'utilisation dans des threads et même au simple appel imbriqué."

    Je ne pense vraiment pas faire appel à la récursion dans ces circonstances, ni aux threads et l'appel imbriqué (n'est ce pas une récursion au premier ordre ?), j'essaie de simplifier le code à l'extrême. Je sais bien qu'avec un OS, il est inutile de se soucier de détails de la compilation, parce que c'est complétement différent du code embarqué, mais là c'est juste le microP et moi, donc ... Je ne sais pas si ce sont des justifications valables.

  12. #12
    Membre éclairé
    Avatar de JMLLB
    Inscrit en
    Septembre 2006
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 285
    Par défaut
    Personnellement je ne vois vraiment pas ce que tu peux gagner à utiliser des variables globales.

    Par contre ce que tu perds est évident:
    -difficulté de reprise du code derrière toi
    -difficulté de comprendre l'évolution de ta variable puisque tout le monde peut y accéder sans synchronisation explicite.
    ...

    Si tu modifie ta variable en la passant par adresse, un simple graphe d'appel peut te permettre de suivre son évolution.

    Ces raisons sont d'autant plus valables si tu fais de l'embarqué car tes moyens de débuggage seront plus réduits que sur un développement simple.
    Et crois moi tu auras déjà de quoi t'amuser sans chercher à partir avec un handicap.

    Si tu fais ton développement dans un cadre professionnel il serait étonnant (et effrayant) que tu n'ai pas de règles de codage spécifiques à l'embarqué qui te précisent quoi et comment faire (interdiction d'allocation dynamique, interdiction des goto, convention de nommage...).
    Si c'est pour un projet perso tu as quand même intérêt a respecter des règles de ce type.

    NB:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    j'essaie de simplifier le code à l'extrême
    c'est le meilleur moyen que je connaisse pour rendre du code incompréhensiblede tout le monde même parfois de son concepteur après quelques mois.

  13. #13
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Par défaut
    En fait je ne suis pas travailleur, je fais ça pour l'école. C'est certain que prendre de bonnes habitudes dès le départ c'est la meilleure façon de ne pas faire n'importe quoi après.

  14. #14
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par kromartien
    En fait je ne suis pas travailleur, je fais ça pour l'école. C'est certain que prendre de bonnes habitudes dès le départ c'est la meilleure façon de ne pas faire n'importe quoi après.
    Alors oublie vite les globales, surtout si elles sont modifiables. A la limite, en lecture seule, pourquoi pas...

    Même en embarqué, j'ai toujours tout fait pour éviter les globales. Même en assembleur et en 8051...

    Des fonctions, des paramètres. C'est tout.

    L'usage des globales produit une simplification apparente et une complication extrême. Crois en les professionnels...

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

Discussions similaires

  1. Variable globale / Propriété des threads
    Par rgarnier dans le forum XMLRAD
    Réponses: 4
    Dernier message: 03/10/2003, 10h49
  2. Cacher Variable Url avec Variable Globale
    Par danuz dans le forum XMLRAD
    Réponses: 6
    Dernier message: 26/09/2003, 17h20
  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