variable globale, problème de link

variable globale, problème de link - C++ - Programmation

Marsh Posté le 02-09-2004 à 08:51:37    

Bonjour, j'ai un autre problème à vous soumettre :
 
Plutôt que de définir des constantes fixes dans mon programme, j'ai créé un fichier dans lesquelles elles sont réunies, de façon à ce que chaque utilisateur puisse avoir son propre fichier de configuration avec des valeurs différentes.
 
Pour introduire ces données dans le programme, j'ai créé une structure dont chaque champ correspond à un paramètre de configuration. Par exemple nom_structure.szDefaultPathName etc. j'ai ensuite une fonction qui prends comme argument une de ces structures, et remplis les champs en fonction du fichier.
Vu que j'ai besoin d'accéder au champs de cette structure dans tous le programme (c'est à dire dans toutes les classes, à chaque fois qu'un des paramètres constant provenant du fichier doit être insérer), j'ai créé une variable globale de la structure d'initialisation, et je l'utilise parout où c'est nécessaire.
J'ai un fichier init.h avec la définition de la structure, le prototype de la fonction d'initialisation, et la déclaration de la variable globale du type de la structure. Le fichier init.cpp contient l'implémentation de la fonction d'initialisation.
 
Pas de problèmes de compilation, mais au moment du linkage, j'obtiens des messages d'erreur du genre :  
Cpmdiag.obj : error LNK2005: "struct s_ini init_data" (?init_data@@3Us_ini@@A) already defined in cpm.obj
 
Mais struct s_ini init_data n'est DEFINIE que dans le fichier init.h, dans les autres fichiers, cette variable globale est utilisée, mais pas redéfinie...
j'utilise VC++6.0, et en configuration DEBUG, le programme est quand même créé (comme s'il s'agissait plus de warnings que d'erreur), mais en RELEASE, pas question de finir le linkage...
 
Ou me suis-je trompé?

Reply

Marsh Posté le 02-09-2004 à 08:51:37   

Reply

Marsh Posté le 02-09-2004 à 10:17:31    

rien compris, balance du code (3 lignes et pas plus)

Reply

Marsh Posté le 02-09-2004 à 10:36:06    

Taz a écrit :

rien compris, balance du code (3 lignes et pas plus)


 :pfff:  
 
init.h :
struct s_ini{
 int nCalib;
 BOOL bHtmlResume;
 string szFilePath;
 double dEvUrbach0;
 double dEvUrbach1;
 double dEvdefauts;
 double dEvcrist;
 int nType;
};
void read_init_file(struct s_ini & init, string szFileName="x" ); //fonction qui remplis les champs d'une struct
struct s_ini init_data; //déclaration variable globale
 
///////////////////////////////////////////
init.cpp
 
initialisation de la variable globale :
 
BOOL CEx06aView::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Modify the Window class or styles here by modifying
 //  the CREATESTRUCT cs
 read_init_file(init_data);
 return CView::PreCreateWindow(cs);
}
 
Puis par exemple, dans diverses classes, appel aux données de cette structure :
 
void CEx06aView::OnCpm()  
{
//blabla  
index_urbach0=c.get_ev_index(init_data.dEvUrbach0);
index_urbach1=c.get_ev_index(init_data.dEvUrbach1);
//blabla
}
mais dans les methode des classe, cette variable globale est utilisée, et non définie...
 
(bon je sais, 3 lignes    :D  )

Reply

Marsh Posté le 02-09-2004 à 10:42:14    

1/ dans init.h : pas de déclaration de la variable globale init_data
2/ dans init.cpp : tu déclare struct s_ini init_data;
3/ dans les autres cpp : tu déclare extern struct s_ini init_data;


Message édité par pains-aux-raisins le 02-09-2004 à 10:46:53
Reply

Marsh Posté le 02-09-2004 à 11:08:53    

+1
Pour éviter d'avoir à redéclarer X fois "extern xxx" dans tous les cpp, un truc : la compile conditionnelle.
 

Code :
  1. init.h
  2. .../...
  3. #ifdef ALLOC_GLOBAL
  4. int toto;
  5. int tata = 93893;     //Avec une valeur de départ  
  6. MaStruct titi;
  7. #else
  8. extern int toto;
  9. extern int tata;      //!!! Ne pas redonner de valeur avec "extern"
  10. extern MaStruct titi;
  11. #endif


 

Code :
  1. init.cpp
  2. #define ALLOC_GLOBAL
  3. #include "init.h"
  4. .../...


 

Code :
  1. <autres modules cpp>
  2. //pas de #define ALLOC_GLOBAL avant #include "init.h"
  3. #include "init.h"
  4. .../...


 
L'autre (gros) avantage, c'est que tes déclarations (allocation et référence "extern" ) sont regroupées dans le même fichier. Quand tu modifie d'un côté, la modif parallèle se trouve juste en dessous. :sol:  
Sinon bonjour les dégats si les deux ne correspondent pas...


---------------
If I want to fail and succeed, which I have done ?
Reply

Marsh Posté le 02-09-2004 à 11:12:54    

+1 :love:
 
Déjà qu'il assimile cette histoire de variable globale et ce sera bien.

Reply

Marsh Posté le 02-09-2004 à 11:29:23    

  1. init.h
   2. .../...
   3. #ifdef ALLOC_GLOBAL
   4. int toto;
   5. int tata = 93893;     //Avec une valeur de départ  
   6. MaStruct titi;
   7. #else
   8. extern int toto;
   9. extern int tata;      //!!! Ne pas redonner de valeur avec "extern"
  10. extern MaStruct titi;
  11. #endif
 
 
 
c'est complètement pourri ta façon de procéder, c'est source d'erreur
 
un .h avec les déclarations extern, un .cpp avec l'allocation des variables :o

Reply

Marsh Posté le 02-09-2004 à 12:16:49    

Taz a écrit :

1. init.h
c'est complètement pourri ta façon de procéder, c'est source d'erreur
 
un .h avec les déclarations extern, un .cpp avec l'allocation des variables :o


 
+1.  
 
Encore mieux, serait de passer par une fonction qui te renvoie un singleton. Du style:  
 

Code :
  1. s_struct * getStructure ()
  2. {
  3.   static s_struct * instance = 0;
  4.   if (!instance)
  5.      instance = new s_struct;
  6.   return instance;   
  7. }


 
Ca évite pas mal de problèmes lors de l'utilisation de l'instance avant le démarrage de main().
 
Edit: j'avais oublié un type.


Message édité par Lam's le 02-09-2004 à 12:17:38
Reply

Marsh Posté le 02-09-2004 à 13:21:01    

Merci pour votre aide, je vais essayer.
C'est vrai que les variables globales je ne maîtrise pas, car je m'en suis toujours passé jusqu'à présent...
 
EDIT :  
j'ai utilisé la technique de pains-aux-raisins, et ça marche très bien. J'avais complétement oublié le coup du external. Encore merci


Message édité par glaurung le 02-09-2004 à 13:54:33
Reply

Marsh Posté le 02-09-2004 à 13:51:56    

Sur l'exemple de Lam's : et la struct on la libère pas ?
 
http://forum.hardware.fr/hardwaref [...] 5867-1.htm


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 02-09-2004 à 13:51:56   

Reply

Marsh Posté le 02-09-2004 à 13:53:35    

bien essayé, mais n'attends pas trop de quelqu'un qui ne manipule que des struct ...

Reply

Marsh Posté le 02-09-2004 à 14:01:53    

BlackGoddess a écrit :

Sur l'exemple de Lam's : et la struct on la libère pas ?
 
http://forum.hardware.fr/hardwaref [...] 5867-1.htm


 
Bof, ça sert à rien de la détruire si sa durée de vie est celle du programme. Sinon, tu rajoutes ça dans ton cpp

Code :
  1. namespace
  2. {
  3.   struct Cleaner
  4.   {
  5.     ~Cleaner() { delete getStructure(); }
  6.   }
  7.   Cleaner cleaner;
  8. }


 
Voilà, c'est assez "spirit of the C++" pour vous ?  :)  
 
Sinon, je tenais à dire par rapport au topic que tu as lié, que je suis un fervent opposant au singleton façon GoF : ça marche très mal lors de l'initialisation des variables statiques.

Reply

Marsh Posté le 02-09-2004 à 14:12:54    

Taz a écrit :


c'est complètement pourri ta façon de procéder, c'est source d'erreur
un .h avec les déclarations extern, un .cpp avec l'allocation des variables :o


 :jap: Merci, Taz, apparemment tu serais l'unique personne a maîtriser l'unique technique de codage. Comme s'il en existait qu'une seule. Je parle des techniques et non des personnes. Parce que des personnes qui pensent détenir le savoir unique : désolé mais tu n'est pas le seul. Sans parler de CET exemple précis, simplement quand tu critiques un post - que ce soit de manière négative ou même positive - ça serait pas mal d'expliquer pourquoi.
Maintenant, pour reprendre CET exemple :
- qqu'un pose une question précise et cherche des réponses précises à SON problème.
- il n'est pas forcément très utile de refaire le monde en général et le débat sur les variables globales en particulier
- "c'est source d'erreur un .h avec les déclarations extern". Par curiosité, as-tu déjà parcouru les fichiers .h de ton compilateur ? Curieux, avec mon compilo (C++ Builder) je trouve des centaines de déclarations de variable globales en "extern".
 
Pour Lam's :
T'aurais pas *encore* plus compliqué ?
Où as-tu vu que la structure à allouer était un objet avec un constructeur ?
Quel est le besoin impératif de passer par un "new" ?
Une bonne vieille variable globale ne serait-elle pas plus simple ?
Ok, ok, il y a des risques (quelle façon de procéder n'en a pas ???) avec les globales. La soluce s'appelle : test et debug.

Reply

Marsh Posté le 02-09-2004 à 14:19:45    

lsdyoyo a écrit :


Pour Lam's :
T'aurais pas *encore* plus compliqué ?
Où as-tu vu que la structure à allouer était un objet avec un constructeur ?
Quel est le besoin impératif de passer par un "new" ?
Une bonne vieille variable globale ne serait-elle pas plus simple ?
Ok, ok, il y a des risques (quelle façon de procéder n'en a pas ???) avec les globales. La soluce s'appelle : test et debug.


 
Oh, j'aurais pu passer par un template, c'est vrai ;)
 
Nan, plus simplement, le premier bout de code que j'ai posté est ce que j'ai trouvé de plus "efficace" pour mes problèmes de variable globales de manière générale. Une variable globale peut poser beaucoup de problèmes (comme tu le dit, on va pas refaire le débat).  
 
Le deuxième bout de code, c'est plus une moquerie aux "puristes" du C++.
 
Quand au new, c'est pour éviter de passer par les références, qui peuvent souvent être confuses. Pas besoin de constructeur pour ça.
 
Maintenant, la meilleure solution, elle existe : c'est celle que l'on comprend, qui fonctionne, et qui demande le moins de temps à implémenter et à maintenir. Donc à chaque développeur ses petites habitudes...
 
Voilà, pas besoin de se facher...

Reply

Marsh Posté le 02-09-2004 à 14:21:11    

:)

Reply

Marsh Posté le 02-09-2004 à 14:28:25    

lsdyoyo > commence par comprendre ce que je dis et arrête de transformer mes propos.

Reply

Marsh Posté le 02-09-2004 à 14:47:56    

Tu voulais peut-être faire :
- Dans le .h : les extern
- Dans un seul des .cpp : les allocations
Pourquoi pas ? Je trouve très bien d'avoir les deux dans un .h : un seul fichier à modifier/vérifier.
En quoi est-ce "pourri" ?


Message édité par lsdYoYo le 02-09-2004 à 14:48:24
Reply

Marsh Posté le 04-09-2004 à 00:42:22    

oui, il faut faire comme ça, c'est la matière canonique. pourquoi ? parce qu'en fin de compte, c'est la même chose que tu fais avec ton #define conditionel : la présence de l'allocation dans une seule unité de traduction. Alors entre gérer ça à la main, avec les risques d'erreurs, et se contenter de faire un fichier, y a pas à choisir. sinon n'oublie pas de faire exactement la même chose pour toutes les fonctions, interdis toi les .c (allez, je te laisse le main).

Reply

Marsh Posté le 04-09-2004 à 15:05:44    

Taz a écrit :

1. init.h
   2. .../...
   3. #ifdef ALLOC_GLOBAL
   4. int toto;
   5. int tata = 93893;     //Avec une valeur de départ  
   6. MaStruct titi;
   7. #else
   8. extern int toto;
   9. extern int tata;      //!!! Ne pas redonner de valeur avec "extern"
  10. extern MaStruct titi;
  11. #endif
 
 
 
c'est complètement pourri ta façon de procéder, c'est source d'erreur
 
un .h avec les déclarations extern, un .cpp avec l'allocation des variables :o


 
A la limite, il peut définir les valeurs dans le .h, mais dans ce cas, il faut les définir en constantes :
const int tata = 93893;  
Ne pas oublier de proteger le fichier contre l'inclusion multiple aussi, des fois que, dans un sursaut d'étourderie ...

Reply

Marsh Posté le 04-09-2004 à 15:29:06    

ouais c'est que je dis, c'est source d'erreur ce truc, ça fait 20 ans qu'on fait un .h et un .c on va se faire chier à faire une méthode qui est dangereuse

Reply

Marsh Posté le 21-04-2005 à 11:05:24    

lsdYoYo a écrit :

+1

Code :
  1. init.h
  2. .../...
  3. #ifdef ALLOC_GLOBAL
  4. int toto;
  5. int tata = 93893;     //Avec une valeur de départ  
  6. MaStruct titi;
  7. #else
  8. extern int toto;
  9. extern int tata;      //!!! Ne pas redonner de valeur avec "extern"
  10. extern MaStruct titi;
  11. #endif


 

Code :
  1. <autres modules cpp>
  2. //pas de #define ALLOC_GLOBAL avant #include "init.h"
  3. #include "init.h"
  4. .../...


 


 
Je confirme les propos de Taz quant à dire que c'est source d'erreurs ; par exemple lorsqu'on compile son programme "bout par bout".
Je m'explique : pour les gens qui utilisent  visual sans vouloir se faire chier avec les makefile (j'en fait parti :-D), voilà une situation foireuse :
2 fichiers .cpp incluent init.h
si à la compilation le premier compile bien, le 2eme foire, quand on va recompiler, il ne recompilera pas le 1er (qui a "en lui" la variable globale de créée) et va en recréer une pour le second, la macro ALLOC_GLOBAL étant "nouvelle"
 
Maintenant il me manque surement des connaissances de configuration de visual...

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed