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 :

Ne pas utiliser les "extern"


Sujet :

C

  1. #1
    Membre averti
    Inscrit en
    Décembre 2009
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 17
    Par défaut Ne pas utiliser les "extern"
    Bonjour à tous

    Je vois à gauche et à droite que les le mot-clé extern est "moche". Ou plutôt que sont emploi l'es. Pourquoi ?
    Comment puis-je le remplacer ? Je l'utilise sur des sémaphore entre différente partie de mon code de plus dans un fichier header bien identifier (du genre GlobalVariable.h)

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    L'utilisation d'un correcteur orthographique (de nos jours, intégré à tous les navigateurs internet) est nécessaire ! Merci de faire un effort

    Il y a 2 emplois de extern :
    1. Devant un prototype de fonction : extern void f(int i);
    2. Devant une déclaration de variable globale définie dans une autre unité de compilation : extern int i;


    Dans le cas 1, le mot-clé extern est inutile car il est implicitement rajouté si besoin. Cela peut éventuellement servir à dire que c'est bien une fonction définie dans une autre unité de compilation et non simplement le prototype d'une fonction définie plus bas dans le fichier courant.

    Dans le cas 2, c'est obligatoire pour utiliser une variable globale qui est définie dans un autre fichier.

    Dans les 2, c'est effectivement peu intéressant / moche / contournable :
    1. Un .h doit contenir les déclarations des variables et on inclue le .h du module qu'on souhaite utiliser. extern est comme je l'ai dit inutile et l'éventuellement petit avantage cosmétique n'a pas lieu d'être.
    2. On évite les variables globales et on passe par des fonctions getters / setters et on retombe dans le cas 1.


    Donc oui, souvent, on utilise peu le mot-clé extern. Mais bon, je n'ai personnellement rien contre lui si ce n'est qu'il montre souvent un mauvais découpage en modules comme expliqué ci-avant.

    (du genre GlobalVariable.h)
    *
    Ceci est malheureusement le signe d'une mauvaise modularité de ton application. J'avais commencé à écrire un article là-dessus... Il faut vraiment que je le termine pour expliquer pourquoi...

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 813
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 813
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Il y a 2 emplois de extern :
    1. Devant un prototype de fonction : extern void f(int i);
    2. Devant une déclaration de variable globale définie dans une autre unité de compilation : extern int i;
    Bonjour

    Moi j'en vois un 3°: pour spécifier à l'intérieur d'un bloc que l'on utilise une variable globale (même définie dans la même unité de compilation).

    Exemple

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int var=123;
    int main()
    {
        extern int var;
        printf("%d\n", var);
    }

    Le gros problème des variables globales, c'est qu'elles sont accessibles/modifiables de partout. Et donc il n'y a rien de pire que d'avoir une globale accidentellement modifiée durant l'exécution. Parce qu'ensuite, pour trouver la fonction qui foire, c'est galère.
    Si le programmeur qui a l'intention de taper dans une globale, prend soin de la redéclarer de cette façon dans la fonction qui l'utilise, alors s'il y a un problème la recherche de la fonction incriminée en sera facilitée.

    Mais bien entendu, si on peut ne pas avoir de globales/extern c'est encore mieux...

    Citation Envoyé par ThomasAU Voir le message
    Comment puis-je le remplacer ? Je l'utilise sur des sémaphore entre différente partie de mon code de plus dans un fichier header bien identifier (du genre GlobalVariable.h)
    Si une variable n'est utilisée que dans une fonction, alors elle doit être locale à la fonction.
    Si une variable doit être utilisée dans plusieurs fonctions, alors tu passes la variable aux fonctions incriminées.
    Cela peut t'amener, dans le cadre d'un gros projet, à avoir alors 15/20/50 variables. Dans ce cas tu crées une structure dédiée à la gestion de ton projet (sa configuration en somme) qui contiendra tous les éléments nécessaire à ton projet et que tu remplis dans le main. Ensuite, te suffit de passer la structure (une seule variable) aux fonctions qui en ont l'utilité.

    Dans 99% des cas, les globales sont inutiles/évitables. La seule exception que je connaisse est dans le cas des kill/signaux. La fonction utilisée pour trapper un signal ne peut contenir qu'un seul paramètre: la valeur du signal trappé. Si cette fonction doit interagir sur un autre élément du programme, alors cet élément doit-être mis en global...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Du coup..... http://gradot.wordpress.com/2014/07/...globales-en-c/

    cet élément doit-être mis en global...
    Pourquoi ne pas passer par des getters et des setters ?

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 813
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 813
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Pourquoi ne pas passer par des getters et des setters ?
    Euh ben parce qu'on n'est pas en C++ quoi...

    Nan, plus sérieusement, un getter et un setter reste une fonction quoi. Et comment cette fonction pourrait accéder à ma variable qui se trouve, elle, dans une autre fonction ?

    Démo

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main()
    {
        int x=100;
        signal(SIGUSR1, trap);
        while (1) sleep(10);
    }
     
    int trap(int sig)
    {
         // Je voudrais afficher x lorsque mon prog reçoit un kill -SIGUSR1 depuis l'extérieur. Comment faire ??? Quel getter me permettra ce tour de passe-passe sans mettre x en global ???
    }
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Membre averti
    Inscrit en
    Décembre 2009
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 17
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Dans 99% des cas, les globales sont inutiles/évitables. La seule exception que je connaisse est dans le cas des kill/signaux.
    Justement dans le projet que je code, j'utilise une queue (qui est en somme une file de signaux) et un sémaphore qui gère l'accès. J'ai plusieurs machines à état (pour le moment 7) qui interagissent avec plusieurs sous-systèmes. Ils sont indépendants dans des thread gérés indépendamment (par FreeRTOS). Les extern variables sont donc sur ce type de variable pour le moment.

    Mon problème, que je tente de régler avec ces externes, est que lorsque j'essaye d'accéder à la queue depuis un autre thread, cela me renvoie sur une autre adresse mémoire.

    Citation Envoyé par Sve@r Voir le message
    Si une variable doit être utilisée dans plusieurs fonctions, alors tu passes la variable aux fonctions incriminées.
    Cela peut t'amener, dans le cadre d'un gros projet, à avoir alors 15/20/50 variables. Dans ce cas tu crées une structure dédiée à la gestion de ton projet (sa configuration en somme) qui contiendra tous les éléments nécessaire à ton projet et que tu remplis dans le main. Ensuite, te suffit de passer la structure (une seule variable) aux fonctions qui en ont l'utilité.
    J'aime bien cette idée, mais il faut que je teste si cela prend plus de mémoire ou non (plus de pointeurs ?).



    P.S : Excusez-moi pour ces malencontreuses faute d'orthographe.

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static int x;
    int getX()
    {
        return x;
    }

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 813
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 813
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static int x;
    int getX()
    {
        return x;
    }
    Ben oui mais tu as mis x en global là !!! Tu disais passer par un getter justement pour ne pas avoir à mettre de global...?
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    en fait non.

    L'exemple plus complet, c'est:

    L'en-tête suivant
    Code capitaine.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int ageDuCapitaine();
    void anniversaireCapitaine();

    Le fichier d'implémentation correspondant
    Code capitaine.c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    static int ageCapitaine=42;
    int ageDuCapitaine() {
        return ageCapitaine;
    }
    void anniversaireCapitaine(){
        ++ageCapitaine;
    }

  10. #10
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut
    Citation Envoyé par ThomasAU Voir le message
    Mon problème, que je tente de régler avec ces externes, est que lorsque j'essaye d'accéder à la queue depuis un autre thread, cela me renvoie sur une autre adresse mémoire.
    C'est donc que tu as plusieurs déclarations de ta variable au lieu d'en avoir une seule et les autres en extern.

    Cela peut arriver aussi il me semble si tu as mis toutes les déclarations en extern.
    Certains compilateurs ne vont pas broncher au link mais ne vont rien linker du tout et tu vas te retrouver avec X adresses.

  11. #11
    Membre averti
    Inscrit en
    Décembre 2009
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 17
    Par défaut
    Le problème est résolut parfaitement avec les déclarations en extern. Pour le moment j'utilise le compilateur gcc et non pas un compilateur exotique (ce que je pense pas faire). Toutefois si je dois faire appel à un tel compilateur qui ne reconnaitrait pas les extern, alors je pense faire une transmission de variable.

  12. #12
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 813
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 813
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ThomasAU Voir le message
    Le problème est résolut parfaitement avec les déclarations en extern. Pour le moment j'utilise le compilateur gcc et non pas un compilateur exotique (ce que je pense pas faire). Toutefois si je dois faire appel à un tel compilateur qui ne reconnaitrait pas les extern, alors je pense faire une transmission de variable.
    Déjà un compilo C qui ne connaitrait pas les extern ne peut pas exister. Le extern est incontournable de la programmation modulaire. En effet, chaque module doit se compiler séparément mais chaque module doit déclarer les variables qu'il utilise. Or extern sert justement à indiquer qu'une variable déclarée dans un module X existe déjà ailleurs et qu'il ne faut alors pas lui réserver de mémoire.
    Si tu as des soucis, c'est soit que ta variable globale est mise en extern de partout (donc en fait elle n'est définie nulle part), soit tu as oublié, dans un module, de la mettre en extern. Dans ce cas elle est définie deux fois et le linkeur gueule à l'éditions de liens.
    Pour éviter ce genre de soucis, on définit les variables dans le module qui a le main() et on les déclare en exten dans tous les autres modules.

    Mais bien entendu c'est encore mieux de ne jamais utiliser de globales !!!
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Précision pour la culture.

    Ces modules sont appelés "unités de compilation" dans la norme.
    Chaque module est un des .c initial, une fois préprocessé (donc, entre autre, quand tous les #include ont été faits, récursivement)

  14. #14
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Ben oui mais tu as mis x en global là !!! Tu disais passer par un getter justement pour ne pas avoir à mettre de global...?
    Elle n'est pas globale, elle est statique au fichier et donc non visible depuis les autres unités de compilation. Tu ne peux pas y accéder autrement qu'avec le getter (sauf dans l'unité de compilation courante bien sûr).

    leternel montre en effet un exemple plus complet.

    A ma connaissance, tu ne peux pas réexposer une variable automatique à l'extérieur. Tu es obligé de passer par des variables a linkage externe (comme ma statique ou alors une vraie globale).

  15. #15
    Expert confirmé
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 226
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 226
    Par défaut
    J'ouvre une petite parenthèse , je pense que utilisation de getter/setter soit pas le plus approprié en C ,en C++ get/set pour ma part c'est souvent utilisation de variable qui sont en privé et donc qu'on doit passer par les méthodes pour les modifier/lire.
    En C il n'y a pas ce souci , les structures ont peut les modifier/lire , pour static je le vois seulement pour des variables temporaires mais qui doivent gardé la même valeurs (pas initialisation a chaque appel de la fonction).

  16. #16
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Ca sert si on veut proposer un singleton, ou un pool.
    Avec cette méthode, ta "classe" est automatiquement un singleton, et son instance est l'unité de compilation. (par contre, il faut gérer la destruction).

    C'est exactement ce qu'il se passe avec la SDL, par exemple, qui demande un appel à SDL_Init() et SDL_Quit().

  17. #17
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 813
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 813
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Elle n'est pas globale, elle est statique au fichier et donc non visible depuis les autres unités de compilation. Tu ne peux pas y accéder autrement qu'avec le getter (sauf dans l'unité de compilation courante bien sûr).
    Ouais c'est un peut tiré par les cheveux. Bon je suis d'accord, ça limite les risques mais pas pour l'unité de compilation courante dans laquelle elle reste synonyme de globale. C'est mieux que rien quoi. Mais pas de globale/statique c'est encore mieux non ?

    Citation Envoyé par leternel Voir le message
    C'est exactement ce qu'il se passe avec la SDL, par exemple, qui demande un appel à SDL_Init() et SDL_Quit().
    Bah, c'est un peu le même principe pour tous les outils un peu complexes (malloc/free, fopen/fclose, shmat/shmdt)...
    L'initialisation sert à "initialiser" tous les éléments internes de l'outil (qui peuvent eux-même se trouver dans une structure telle que je l'expliquais dans mon premier post) et la fermeture permettra de "libérer" toutes les ressources éventuellement réservées...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. Ne pas utiliser les versions 3.0, 3.0.1 et 2.31.1
    Par bruno_pages dans le forum BOUML
    Réponses: 0
    Dernier message: 09/10/2007, 23h12
  2. [9i]Ne pas utiliser les rollback segments
    Par loudo dans le forum Oracle
    Réponses: 3
    Dernier message: 15/06/2006, 14h17
  3. [débutant] Ne pas utiliser les frames ?
    Par Pigoulou dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 13/02/2006, 10h09

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