Erreur multiple definition

Fermé
rbarraud - Modifié le 17 janv. 2022 à 12:14
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 17 janv. 2022 à 12:30
Bonsoir,

Dans mon programme il ya le fichier header suivant :
#ifndef __FILE_MESSAGES_H__
#define __FILE_MESSAGES_H__

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


typedef enum {
 BATEAU_DECH,
 BATEAU_CHAR,
 TRAIN_DECH,
 TRAIN_CHAR,
 CAMION_DECH,
 CAMION_CHAR
} TYPE ;


typedef struct {
 long type;
 int pid;
 int nb_conteneurs; 
}demande_quai;


typedef struct {
 long type;
 int portique1[2];
 int portique2[2]; 
}reponse_quai;

typedef struct {
 long type;
 int pid;
 int nb_conteneurs; 
}demande_portique;

typedef struct {
 long type;
 int nb_cont_restants;
}reponse_portique;

int tailleDemandeQuai = sizeof(demande_quai)-sizeof(long);
int tailleReponseQuai = sizeof(reponse_quai)-sizeof(long);
int tailleDemandePortique = sizeof(demande_portique)-sizeof(long);
int tailleReponsePortique = sizeof(demande_portique)-sizeof(long);

void erreur(const char * msg) ;
int init_file_message(void);
void supprimer_file(int msgid);

#endif


qui est inclus dans plusieurs autres fichiers headers comme celui-ci :

#ifndef __VEHICULE_H__
#define __VEHICULE_H__


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>

#include "file_messages.h"

#define TAILLE_BAT 7
#define TAILLE_TRAIN 10
#define TAILLE_CAM 1



void creer_demande_quai(demande_quai *dem_q,int type, int nb_cont);
void creer_demande_portique(demande_portique *dem_p,TYPE type, int pid, int nb_cont);
int vehicule(int msgid_quai,TYPE type);


#endif


Dont les fichiers .c correspondant utilisent les variables tailleDemandeetc définies dans le premiers fichier header ci dessus.

A la compilation j'ai cette erreur :

/usr/bin/ld: /tmp/ccgKSpWC.o:(.data+0x0): multiple definition of `tailleDemandeQuai'; /tmp/ccBivDIA.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/ccgKSpWC.o:(.data+0x4): multiple definition of `tailleReponseQuai'; /tmp/ccBivDIA.o:(.data+0x4): first defined here
/usr/bin/ld: /tmp/ccgKSpWC.o:(.data+0x8): multiple definition of `tailleDemandePortique'; /tmp/ccBivDIA.o:(.data+0x8): first defined here
/usr/bin/ld: /tmp/ccgKSpWC.o:(.data+0xc): multiple definition of `tailleReponsePortique'; /tmp/ccBivDIA.o:(.data+0xc): first defined here
/usr/bin/ld: /tmp/ccgjIMWA.o:(.data+0x0): multiple definition of `tailleDemandeQuai'; /tmp/ccBivDIA.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/ccgjIMWA.o:(.data+0x4): multiple definition of `tailleReponseQuai'; /tmp/ccBivDIA.o:(.data+0x4): first defined here
/usr/bin/ld: /tmp/ccgjIMWA.o:(.data+0x8): multiple definition of `tailleDemandePortique'; /tmp/ccBivDIA.o:(.data+0x8): first defined here
/usr/bin/ld: /tmp/ccgjIMWA.o:(.data+0xc): multiple definition of `tailleReponsePortique'; /tmp/ccBivDIA.o:(.data+0xc): first defined here
/usr/bin/ld: /tmp/ccgjIMWA.o: in function `erreur':
main.c:(.text+0x0): multiple definition of `erreur'; /tmp/ccBivDIA.o:file_messages.c:(.text+0x0): first defined here
/usr/bin/ld: /tmp/ccgSl8NB.o:(.data+0x0): multiple definition of `tailleDemandeQuai'; /tmp/ccBivDIA.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/ccgSl8NB.o:(.data+0x4): multiple definition of `tailleReponseQuai'; /tmp/ccBivDIA.o:(.data+0x4): first defined here
/usr/bin/ld: /tmp/ccgSl8NB.o:(.data+0x8): multiple definition of `tailleDemandePortique'; /tmp/ccBivDIA.o:(.data+0x8): first defined here
/usr/bin/ld: /tmp/ccgSl8NB.o:(.data+0xc): multiple definition of `tailleReponsePortique'; /tmp/ccBivDIA.o:(.data+0xc): first defined here
/usr/bin/ld: /tmp/ccDpXFrA.o:(.data+0x0): multiple definition of `tailleDemandeQuai'; /tmp/ccBivDIA.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/ccDpXFrA.o:(.data+0x4): multiple definition of `tailleReponseQuai'; /tmp/ccBivDIA.o:(.data+0x4): first defined here
/usr/bin/ld: /tmp/ccDpXFrA.o:(.data+0x8): multiple definition of `tailleDemandePortique'; /tmp/ccBivDIA.o:(.data+0x8): first defined here
/usr/bin/ld: /tmp/ccDpXFrA.o:(.data+0xc): multiple definition of `tailleReponsePortique'; /tmp/ccBivDIA.o:(.data+0xc): first defined here
/usr/bin/ld: /tmp/ccszUInB.o:(.data+0x0): multiple definition of `tailleDemandeQuai'; /tmp/ccBivDIA.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/ccszUInB.o:(.data+0x4): multiple definition of `tailleReponseQuai'; /tmp/ccBivDIA.o:(.data+0x4): first defined here
/usr/bin/ld: /tmp/ccszUInB.o:(.data+0x8): multiple definition of `tailleDemandePortique'; /tmp/ccBivDIA.o:(.data+0x8): first defined here
/usr/bin/ld: /tmp/ccszUInB.o:(.data+0xc): multiple definition of `tailleReponsePortique'; /tmp/ccBivDIA.o:(.data+0xc): first defined here


Si quelqu'un a une idée je suis preneur

Bonne soirée


Configuration: Linux / Firefox 95.0

2 réponses

[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
Modifié le 12 janv. 2022 à 15:12
Salut rbarraud,

Tu ne montres pas tes fichiers .c correspondants aux deux .h que tu postes.

Cependant, on y voit les problèmes décrits ci-après qui sont certainement à l'origine de tes erreurs.

Dans file_messages.h tu définis des variables globales :

int tailleDemandeQuai = sizeof(demande_quai)-sizeof(long);
int tailleReponseQuai = sizeof(reponse_quai)-sizeof(long);
int tailleDemandePortique = sizeof(demande_portique)-sizeof(long);
int tailleReponsePortique = sizeof(demande_portique)-sizeof(long);


Les .h ne doivent se contenter que de définir des types, des prototypes de fonctions, des #define, mais pas des variables (ni l'implémentation des fonctions, etc., l'implémentation étant réservée aux .c).

Autrement, à chaque usage de l'entête, les variables vont être redéfinies.

Pour éviter ce problème, si tu tiens vraiment à disposer de variables globales auxquelles tu puisses te référer pour les utiliser dans différents fichiers .c en faisant un
#include file_messages.h"
tu dois :
  • déclarer ces variables avec le mot clef
    extern
    dans le fichier .h
  • faire ta déclaration dans le fichier .c correspondant


Le mot clef extern te permet de déclarer l'existence de cette variable, qui sera connue donc de l'utilisateur de l'entête, sans la définir, la définition devant se trouver dans l'un des autres fichiers compilés (en général le fichier .c qui correspond au .h), cette vérification étant faite au stade de la liaison et non de la compilation.

Tu as le même type de problème dans l'autre entête, qui définit
int vehicule(int msgid_quai,TYPE type);
.

Je te recommande la lecture de ce document très clair et complet sur le bon usage des .h en C :

http://websites.umich.edu/~eecs381/handouts/CHeaderFileGuidelines.pdf

Dal
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
Modifié le 12 janv. 2022 à 15:25
Note quand même que l'usage de variables globales est en général à décourager.

Tu peux souvent faire mieux en encapsulant les valeurs dont tu as besoin dans un "objet" de type struct, que tu passes en argument des fonctions qui en ont besoin sous la forme d'un pointeur.

Cela permet de rendre ton code plus générique et réutilisable, et ta conception plus lisible.
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
Modifié le 17 janv. 2022 à 12:36
Bonjour,

La définition multiple est dues au variables globale. Le header dans lequel elles sont définies est importé dans plusieurs fichiers
.c
et donc présente dans chaque
.o
engendré. Au moment de linker (c'est à dire de rassembler tous les
.o
pour former le binaire finale) ces variables globales existent donc en autant d'exemplaire.

Comme le dit [Dal] c'est l'une des (nombreuses) raisons pour lesquelles il faut éviter les variables globales. Outre les problèmes de linkage, elles posent aussi des problèmes de lisibilité (on ne sait pas qui les modifie et qui en a besoin) et d'implémentation (notamment quand on commence à paralléliser le code). Et comme le dit [Dal], il suffit de passer les variables adéquates en paramètres aux fonctions (à voir si cela fait sens ou pas de les déclarer au travers d'une structure comme il le propose, mais selon moi tu ne devrais le faire que si cela a un sens "sémantique" de les rassembler, sinon, autant les passer chacune indépendamment en paramètre).

Par contre il y a deux manières à mon avis plus élégantes de contourner ton problème.

Méthode 1 : avec des
#define


Pour rappel, les
#define
sont résolus par le précompilateur (l'identifiant est substitué par sa valeur par le précompilateur). Il n'y aucune "intelligence" dans le précompilateur, c'est le compilateur qui une fois la substitution faite verra si le code engendré a un sens.

#define tailleDemandeQuai sizeof(demande_quai) - sizeof(long)
#define tailleReponseQuai sizeof(reponse_quai) - sizeof(long)
#define tailleDemandePortique sizeof(demande_portique) - sizeof(long)
#define tailleReponsePortique sizeof(demande_portique) - sizeof(long)


Note que comme il s'agit d'une substitution, il n'y a pas de
=
entre l'identifiant de la macro et sa valeur. Note également qu'il ne faut surtout pas mettre de
;
en fin de ligne, sans quoi le pré-compilateur injectera des
;
à des endroits inopportuns.

Méthode 2 : par "héritage"

Le fait que tu aies besoin de ces tailles laisse entendre que l'ajout du
long
dans chacune de tes structures définit un autre objet. Tu pourrais donc réécrire :

typedef struct {
    long type;
    int portique1[2];
    int portique2[2]; 
} reponse_quai;


... ainsi :

typedef struct {
    int portique1[2];
    int portique2[2]; 
} reponse_quai;

typedef struct {
    struct reponse_quai reponse_quai;
    long type;
} reponse_quai_ext;


Ensuite, il te suffit d'utiliser soit
sizeof(reponse_quai)
, soit
sizeof(reponse_quai_ext)
.

Cependant, cela altère la manière dont tu accèdes aux portiques quand u manipules un
reponse_quai_ext rqe
: il faudra par exemple écrire ;
rqe.reponse_quai.portique1[0]
. Bref, la méthode 2 est plus contraignante pour adapter ton code que la méthode 1.

Note qu'avec cette seconde méthode, tu peux caster une instance de
reponse_quai_ext
en
reponse_quai
, sous réserve que l'attribut
reponse_quai
soit le premier attribut de
struct reponse_quai_ext
. C'est comme ça qu'on fait de "l'héritage" (au sens C++) en C (qui ne propose pas nativement de notion d'héritage).

Bonne chance
0