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 :

Variable const global


Sujet :

C++

  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 209
    Points
    23 209
    Par défaut Variable const global
    Bonjour,

    Je suis actuellement en train de faire une classe "Logger".
    J'ai donc fait un singleton pouvant gérer un tableau d'instance de cette classe.
    A côté j'ai quelques paramètres qui doivent rester fixe, pour ceci j'utilise des tableau constants.
    Mais je suis confronté à un petit problème :
    /media/Acer/Users/Neckara/Desktop/Donnees/Projet/Console/Console/logger.cpp:88: undefined reference to `LD::LOGGER_PARAM::taille_buffer'
    Or ce que je ne m'explique pas c'est que pour la variable chemin, il n'a aucune difficulté pour trouver sa référence :

    Param.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
    16
    17
    18
    #ifndef PARAM_H
    #define PARAM_H
     
     
    namespace LD
    {
        //[...]
     
        /** @brief Options relative au fichier de log */
        namespace LOGGER_PARAM
        {
            /** @brief nomination des différents fichiers de logs. MAX est le nombre de fichiers de logs connus. Il doit toujours être placé à la fin */
            typedef enum{DEFAULT, MAX}IdLog;
     
        }
    }
     
    #endif // PARAM_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
    16
    17
    18
    19
    20
    //param.cpp
    #include "Param.h"
     
     
    namespace LD
    {
        //....
     
        /** @brief Options relative au fichier de log */
        namespace LOGGER_PARAM
        {
     
            /** @brief donne les chemins où écrire les différents fichiers de logs */
            const char * chemin[MAX] = {"erreur.log"};
     
     
            /** @brief donne les tailles des buffers pour les différents fichiers de logs */
            const int taille_buffer[MAX] = {500};
        }
    }
    La ligne incriminée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    instance[id] = new Logger(LOGGER_PARAM::chemin[id], LOGGER_PARAM::taille_buffer[id]);
    //par contre aucun problème avec chemin
    Si je met ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    instance[id] = new Logger(LOGGER_PARAM::chemin[id], 50/* LOGGER_PARAM::taille_buffer[id] */);
    Tout fonctionne correctement...

    Plus haut dans le même fichier on trouve :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        namespace LOGGER_PARAM
        {
            extern const char * chemin[MAX];
            extern const int taille_buffer[MAX];
        }
    Le tout étant dans le namespace LD bien sûr.

    Auriez-vous une idée ?

    Merci d'avance,
    Neckara

    EDIT : j'avais oublier de mettre un const :
    const char * const chemin[MAX];
    Et là il ne trouve plus du tout chemin.
    J'ai donc essayé d'enlever le const pour taille_buffer et tout d'un coup il arrive à le trouver...

    Donc pourquoi est-ce que de mettre ou de ne pas mettre une variable en constante fait qu'il ne la trouve plus lors de l'édition de lien?
    Je précise que j'ai bien répercuté chaque modifications sur la déclaration de la variable en extern et sur la "vrai" déclaration de la variable.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 209
    Points
    23 209
    Par défaut
    Problème résolu :

    const a par défaut une visibilité locale (= static), c'est donc différent du C où il est exposé à l'édition de lien.

    Il faut donc même lors de sa déclaration rajouter le mot clé "extern".

  3. #3
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    A ceux qui renverraient un peu trop vite sur cet article (excellent par ailleurs), n'oubliez pas de consulter la troisième partie qui traite justement du Logger.
    Find me on github

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Problème résolu :

    const a par défaut une visibilité locale (= static), c'est donc différent du C où il est exposé à l'édition de lien.

    Il faut donc même lors de sa déclaration rajouter le mot clé "extern".
    DRY : la déclaration avec extern devrait être dans un en-tête inclus par tous ceux qui en ont besoin y compris le fichier source définissant les variables. Ca évite de facto ce genre de pb

    Je reste très sceptique sur l'utilisation des variables globales chemins et taille_buffer qui devraient probablement être des paramètres locaux de la fabrique des loggers.

    @jb : sauf que je ne suis pas persuadé qu'on a besoin d'accéder au journal depuis n'importe quel point du code. Et si cela devait être le cas, je regretterait probablement de ne pas avoir un meilleur support d'AOP intégré au langage pour éviter ce singleton.

  5. #5
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 209
    Points
    23 209
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    DRY : la déclaration avec extern devrait être dans un en-tête inclus par tous ceux qui en ont besoin y compris le fichier source définissant les variables. Ca évite de facto ce genre de pb
    C'est ce que j'ai fait dès que j'ai trouvé le problème

    Citation Envoyé par 3DArchi Voir le message
    Je reste très sceptique sur l'utilisation des variables globales chemins et taille_buffer qui devraient probablement être des paramètres locaux de la fabrique des loggers.
    Ce sont des paramètres qui doivent rester constant du début à la fin du programme.
    Mais il peut arriver qu'on ai besoin de modifier ces paramètres. J'ai donc créé deux fichiers (un .h et un .cpp) pour regrouper tous les paramètres ce qui simplifie énormément la modification de ceux-ci.
    De plus, l'utilisateur n'a pas besoin de manipuler ces paramètres :
    J'ai défini un typedef enum {DEFAULT, ERREURS, TOTO,MAX}IdLog;. Il suffit donc de manipuler uniquement ces valeurs. Mes fonctions se chargeant de prendre dans mes tableaux constants les bonnes valeur pour les paramètres.
    Malgré tout, l'utilisateur peut consulter les valeurs de ces paramètres s'il le souhaite.

    Citation Envoyé par 3DArchi Voir le message

    @jb : sauf que je ne suis pas persuadé qu'on a besoin d'accéder au journal depuis n'importe quel point du code. Et si cela devait être le cas, je regretterait probablement de ne pas avoir un meilleur support d'AOP intégré au langage pour éviter ce singleton.
    Une erreur pouvant survenir en tout point du code, il faut donc pouvoir écrire dans le fichier de log en tout point du code.

    Sinon je ne vois pas trop le problème, l'utilisation est très simple :
    Le programmeur peut ajouter/modifier/supprimer des fichiers de logs selon les besoins de son programme dans les fichiers param.

    Et ensuite on a trois instructions :
    - écrire(IdLog, const string &);
    - fermerTousLesFichiersDeLog();
    - changerFichierLog(IdLog);

    Le nom du fichier de log est la concaténation du chemin ainsi que de la date.
    changerFichierLog() permet de fermer le fichier en cours et de recalculer le nom du fichier de log pour éventuellement avoir un fichier de log par jour, semaine, mois ou année.

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Ce sont des paramètres qui doivent rester constant du début à la fin du programme.
    Mais il peut arriver qu'on ai besoin de modifier ces paramètres. J'ai donc créé deux fichiers (un .h et un .cpp) pour regrouper tous les paramètres ce qui simplifie énormément la modification de ceux-ci.
    De plus, l'utilisateur n'a pas besoin de manipuler ces paramètres :
    J'ai défini un typedef enum {DEFAULT, ERREURS, TOTO,MAX}IdLog;. Il suffit donc de manipuler uniquement ces valeurs. Mes fonctions se chargeant de prendre dans mes tableaux constants les bonnes valeur pour les paramètres.
    Malgré tout, l'utilisateur peut consulter les valeurs de ces paramètres s'il le souhaite.
    Tes paramètres ont ici une portée globale, c'est à dire qu'ils injectent une dépendance potentiellement dans tous tes modules. Or de ce que j'en comprends, c'est probablement inutile car le seul endroit où ils sont nécessaires ce doit être lors de la construction du logger. Peut être l'interface du système de log a-t-elle des lacunes ?


    Citation Envoyé par Neckara Voir le message
    Une erreur pouvant survenir en tout point du code, il faut donc pouvoir écrire dans le fichier de log en tout point du code.
    C'est là où je ne partage pas cet avis.

    ==> Qu'est-ce qu'une erreur ?

    1/ Un comportement inattendu aux interfaces de ton système: le 'monde extérieur' (IHM, OS, fichier, micro, réseau, etc...) donne un résultat hors du domaine de validité souhaité (mauvaise saisie de l'utilisateur, disque plein, fichier inexistant, protocole violé, etc...).
    2/ Une rupture du contrat : là je ne vois pas d'autre mot que bug
    3/ Un état particulier du métier : ici l'environnement extérieur se comporte comme on s'y attend et le code fonctionne parfaitement, c'est le domaine qui dit que cet état doit être considéré comme 'anormal'. Quelques exemples : une licence périmée, une détection d'intrusion, une daté échue, un accumulateur saturée, un auto diagnostic, la modification d'un paramètre, etc....

    Les cas (1) et (3) sont très localisés dans le code et ne concernent donc pas n'importe quel point du code.

    Reste le cas (2):
    => en PPC, c'est là où j'aurais aimé avoir un peu plus de support par exemple via de l'AOP pour pouvoir tracer les ruptures de contrat à l'extérieur de la fonction. Ceci dit, cela suppose que toute tes fonctions commencent et se terminent par quelque chose comme VERIFIER_CONTRAT() qui lui-même fait appel à la journalisation en cas de problème.

    => en programmation défensive (qui peut être vu comme une précondition à 'toujours vraie') : là en cas de problème, une exception peut être levée. Seul l'endroit où est traitée l'exception a besoin d'accéder au journal. Et le catch peut se trouver très très au dessus dans la pile d'appel.

    Le système de journalisation n'a donc pas besoin d'être vu partout

    Il y a un aspect que j'ai volontairement omis qui est le log de debug. Là on n'est pas à mon sens dans la journalisation d'un système mais dans l'instrumentation du code en mode boîte blanche ce qui est assez différent et n'a pas vocation à exister au delà de certaines phases de tests.

    [EDIT] dit autrement: il y a une différence entre où survient une erreur, où elle est détectée et où elle est traitée. Ces trois évènements peuvent ne pas être localisés au même endroit et seul le dernier a réellement besoin d'accéder à la journalisation

  7. #7
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 209
    Points
    23 209
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Tes paramètres ont ici une portée globale, c'est à dire qu'ils injectent une dépendance potentiellement dans tous tes modules. Or de ce que j'en comprends, c'est probablement inutile car le seul endroit où ils sont nécessaires ce doit être lors de la construction du logger. Peut être l'interface du système de log a-t-elle des lacunes ?
    Comment faire alors pour pouvoir regrouper tous les paramètres au sein d'un même fichier tout en gardant une lisibilité locale ?

    EDIT : pour le chemin, le programmeur peut décider de faire afficher le nom du fichier de log à l'utilisateur du programme, dans ce cas là, est-ce qu'une fonction serait mieux? Car au final, ceci reviendrait exactement au même.


    Citation Envoyé par 3DArchi Voir le message
    => en programmation défensive (qui peut être vu comme une précondition à 'toujours vraie') : là en cas de problème, une exception peut être levée. Seul l'endroit où est traitée l'exception a besoin d'accéder au journal. Et le catch peut se trouver très très au dessus dans la pile d'appel.

    Le système de journalisation n'a donc pas besoin d'être vu partout

    Il y a un aspect que j'ai volontairement omis qui est le log de debug. Là on n'est pas à mon sens dans la journalisation d'un système mais dans l'instrumentation du code en mode boîte blanche ce qui est assez différent et n'a pas vocation à exister au delà de certaines phases de tests.

    [EDIT] dit autrement: il y a une différence entre où survient une erreur, où elle est détectée et où elle est traitée. Ces trois évènements peuvent ne pas être localisés au même endroit et seul le dernier a réellement besoin d'accéder à la journalisation
    En effet, le catch peut se trouver très haut dans la pile d'appel mais ce n'est pas forcément le cas. Certaines erreurs peuvent être traitée localement pour ensuite pouvoir poursuivre le traitement. La position du catch dépend surtout de l'erreur et de ses conséquences.
    De plus certaines "erreurs" peuvent être aussi des warnings qui elles ne génèreront pas d'exceptions.


    Ensuite, je ne vais pas gérer uniquement des fichiers de logs d'erreurs mais aussi d'autres fichiers qui devront enregistrer diverses informations.
    Or dans ce cas là, ces fichiers pourront contenir plusieurs types d'informations provenant de modules éloignés.

    De plus le système de journalisation (pas les paramètres) ne sera visible que des modules incluant "logger.h".
    Si je devait créer une classe GestionLogger, il faudrait alors que je transmette une référence/pointeur à chaque fonction l'utilisant mais il faudrait mettre un mutex (global ou statique) de partout car on ne peut pas garantir que l'instance de la classe GestionLogger n'ai pas été détruite par un autre thread.
    Je pense donc que c'est encore pire que de mettre 3 méthodes statiques surtout que le mutex mal utilisé pourrait bloquer tout le code sans que l'utilisateur comprenne pourquoi.

    EDIT : il faudrait aussi que je garantisse qu'il n'existe qu'une seule classe GestionLogger, ça me faire revenir à un pattern de singleton, je vois mal comment faire sans.

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

Discussions similaires

  1. variables const globales et locales
    Par Mokhtar BEN MESSAOUD dans le forum Débuter
    Réponses: 2
    Dernier message: 26/02/2008, 16h14
  2. Variable environnement / globale
    Par crochepatte dans le forum Langage
    Réponses: 14
    Dernier message: 18/09/2006, 10h55
  3. Variable super globale au projet
    Par florent149 dans le forum Général VBA
    Réponses: 35
    Dernier message: 11/07/2006, 11h52
  4. Réponses: 4
    Dernier message: 20/06/2005, 16h04
  5. [.NET] [C#] Variable super global ?
    Par choas dans le forum Windows Forms
    Réponses: 4
    Dernier message: 15/04/2005, 16h27

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