Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

probleme de declaration/definition de variables et linkage

26 réponses
Avatar
Vincent Lefevre
Bonjour,

Dans

http://search.cpan.org/CPAN/authors/id/I/IL/ILYAZ/modules/Term-Gnuplot-0.5705.tar.gz

il y a un fichier Gnuplot.h contenant en particulier:

typedef int TBOOLEAN;
[...]
extern TBOOLEAN screen_ok;
[...]
TBOOLEAN screen_ok;

La ligne "TBOOLEAN screen_ok;" est probablement une erreur, mais
quelle est son effet du point de vue de la norme, sachant qu'on
a la même chose ailleurs et que les deux fichiers objets seront
linkés ensemble (cf ci-dessous)?

À cause de cette ligne, le linkeur se plaint:

LD_RUN_PATH="/opt/local/lib" env MACOSX_DEPLOYMENT_TARGET=10.3 cc -L/opt/local/lib -bundle -undefined dynamic_lookup -L/usr/local/lib Gnuplot.o -o blib/arch/auto/Term/Gnuplot/Gnuplot.bundle ./gnuterm/libgnuterm.a -lm -lgd -lpng -lz
/usr/bin/ld: multiple definitions of symbol _screen_ok
Gnuplot.o definition of _screen_ok in section (__DATA,__common)
./gnuterm/libgnuterm.a(util.o) definition of _screen_ok in section (__DATA,__common)
collect2: ld returned 1 exit status

Une telle erreur est-elle normale (source C incorrect) ou s'agit-il
d'un bug de l'implémentation? Je n'arrive pas à la reproduire sur
un exemple simple.

Note: je dis bien "à cause de cette ligne", car si je l'enlève,
je n'ai plus d'erreur.

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

10 réponses

1 2 3
Avatar
Harpo
Vincent Lefevre wrote:

Bonjour,

Dans


http://search.cpan.org/CPAN/authors/id/I/IL/ILYAZ/modules/Term-Gnuplot-0.5705.tar.gz


il y a un fichier Gnuplot.h contenant en particulier:

typedef int TBOOLEAN;
[...]
extern TBOOLEAN screen_ok;
[...]
TBOOLEAN screen_ok;

La ligne "TBOOLEAN screen_ok;" est probablement une erreur, mais
quelle est son effet du point de vue de la norme, sachant qu'on
a la même chose ailleurs et que les deux fichiers objets seront
linkés ensemble (cf ci-dessous)?

À cause de cette ligne, le linkeur se plaint:

LD_RUN_PATH="/opt/local/lib" env MACOSX_DEPLOYMENT_TARGET.3 cc
-L/opt/local/lib -bundle -undefined dynamic_lookup -L/usr/local/lib
Gnuplot.o -o blib/arch/auto/Term/Gnuplot/Gnuplot.bundle
./gnuterm/libgnuterm.a -lm -lgd -lpng -lz /usr/bin/ld: multiple
definitions of symbol _screen_ok Gnuplot.o definition of _screen_ok in
section (__DATA,__common) ./gnuterm/libgnuterm.a(util.o) definition of
_screen_ok in section (__DATA,__common) collect2: ld returned 1 exit
status

Une telle erreur est-elle normale (source C incorrect) ou s'agit-il
d'un bug de l'implémentation? Je n'arrive pas à la reproduire sur
un exemple simple.

Note: je dis bien "à cause de cette ligne", car si je l'enlève,
je n'ai plus d'erreur.


C'est à ce qui me semble une erreur.
screen_ok est déclaré dans util.c, or les autres sources comme Gnuplot.c
qui incluent le .h le déclare aussi.
Comme il est peu raisonnable de penser que le package n'ait pas été
testé, il doit y avoir une différence entre leur compilateur et le
tien, peut-être le leur génère une référence externe lorsqu'il voit à
la fois une déclaration avec et sans extern.
Je ne connais pas la norme à ce sujet mais la ligne que tu as enlevée
n'avait aucune utilité et ne marche pas au moins chez toi.
Cela mérite un rapport de bug.

Avatar
Emmanuel Delahaye
http://search.cpan.org/CPAN/authors/id/I/IL/ILYAZ/modules/Term-Gnuplot-0.5705.tar.gz

il y a un fichier Gnuplot.h contenant en particulier:

typedef int TBOOLEAN;
[...]
extern TBOOLEAN screen_ok;
[...]
TBOOLEAN screen_ok;

La ligne "TBOOLEAN screen_ok;" est probablement une erreur,


Absolument. Il ne devrait pas y avoir de définition d'objet dans un
header. A supprimer. Point.

mais
quelle est son effet du point de vue de la norme, sachant qu'on
a la même chose ailleurs et que les deux fichiers objets seront
linkés ensemble (cf ci-dessous)?


Définitions multiples si le header est inclus dans plus d'une unité de
compilation. C'est un bug.

À cause de cette ligne, le linkeur se plaint:

LD_RUN_PATH="/opt/local/lib" env MACOSX_DEPLOYMENT_TARGET.3 cc -L/opt/local/lib -bundle -undefined dynamic_lookup -L/usr/local/lib Gnuplot.o -o blib/arch/auto/Term/Gnuplot/Gnuplot.bundle ./gnuterm/libgnuterm.a -lm -lgd -lpng -lz
/usr/bin/ld: multiple definitions of symbol _screen_ok
Gnuplot.o definition of _screen_ok in section (__DATA,__common)
./gnuterm/libgnuterm.a(util.o) definition of _screen_ok in section (__DATA,__common)
collect2: ld returned 1 exit status


Normal.

Une telle erreur est-elle normale (source C incorrect) ou s'agit-il
d'un bug de l'implémentation? Je n'arrive pas à la reproduire sur
un exemple simple.


int a;
int a;

int main(void)
{
return 0;
}

Compiling: main.c
main.c:8: warning: redundant redeclaration of 'a'
main.c:7: warning: previous declaration of 'a' was here
Linking console executable: C:devforumsOP1.exe
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 2 warnings

Ce warning me suffit pour considérer qu'il y a un problème. (gcc est un
peu 'avale-tout')

D'autres compilateurs pourraient rejeter ce code.

--
A+

Emmanuel Delahaye

Avatar
Vincent Lefevre
Dans l'article <43a52d93$0$9487$,
Emmanuel Delahaye écrit:

Définitions multiples si le header est inclus dans plus d'une unité de
compilation. C'est un bug.


Ceci dit, sur un exemple similaire plus simple (comme le tien ci-dessous),
le même compilateur ne bronche pas.

int a;
int a;

int main(void)
{
return 0;
}

Compiling: main.c
main.c:8: warning: redundant redeclaration of 'a'
main.c:7: warning: previous declaration of 'a' was here
Linking console executable: C:devforumsOP1.exe
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 2 warnings

Ce warning me suffit pour considérer qu'il y a un problème. (gcc est
un peu 'avale-tout')


Même gcc -Wall ne donne aucun warning. Est-ce un bug dans gcc?
La norme impose-t-elle un diagnostic dans un tel cas?

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Harpo
Emmanuel Delahaye wrote:

il y a un fichier Gnuplot.h contenant en particulier:

typedef int TBOOLEAN;
[...]
extern TBOOLEAN screen_ok;
[...]
TBOOLEAN screen_ok;

La ligne "TBOOLEAN screen_ok;" est probablement une erreur,


Absolument. Il ne devrait pas y avoir de définition d'objet dans un
header.


C'est pourtant ce qui est généralement fait, à moins que je n'aie
interverti les définitions de 'définition' et 'déclaration'.


Avatar
Emmanuel Delahaye
Emmanuel Delahaye wrote:


il y a un fichier Gnuplot.h contenant en particulier:

typedef int TBOOLEAN;
[...]
extern TBOOLEAN screen_ok;
[...]
TBOOLEAN screen_ok;

La ligne "TBOOLEAN screen_ok;" est probablement une erreur,


Absolument. Il ne devrait pas y avoir de définition d'objet dans un
header.


C'est pourtant ce qui est généralement fait, à moins que je n'aie
interverti les définitions de 'définition' et 'déclaration'.


http://mapage.noos.fr/emdel/notes.htm#definitions

--
A+

Emmanuel Delahaye



Avatar
Vincent Lefevre
Dans l'article <43a54737$0$14929$,
Emmanuel Delahaye écrit:

http://mapage.noos.fr/emdel/notes.htm#definitions


"Notons que par conséquent, une déclaration est aussi une
définition, mais que l'inverse n'est pas toujours vrai."

Cette page ne mélangerait pas les deux notions?

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Emmanuel Delahaye
Dans l'article <43a54737$0$14929$,
Emmanuel Delahaye écrit:


http://mapage.noos.fr/emdel/notes.htm#definitions



"Notons que par conséquent, une déclaration est aussi une
définition, mais que l'inverse n'est pas toujours vrai."

Cette page ne mélangerait pas les deux notions?


Je me le demande !

Va pour :

"Notons que par conséquent, une définition est aussi une
déclaration, mais que l'inverse n'est pas toujours vrai."

Correction faite.

--
A+

Emmanuel Delahaye


Avatar
Harpo
Emmanuel Delahaye wrote:

Absolument. Il ne devrait pas y avoir de définition d'objet dans un
header.


C'est pourtant ce qui est généralement fait, à moins que je n'aie
interverti les définitions de 'définition' et 'déclaration'.


http://mapage.noos.fr/emdel/notes.htm#definitions


J'ai donc du confondre comme souvent, mais c'est très confusant.

Lorsqu'on ecrit 'typedef int X;', il s'agit d'une déclaration et on
aurait du appeler 'typedef' 'typedecl'.
D'ailleurs, je sens que je vais le faire et mettre
#define typedecl typedef
en tête de mes sources... cela augmentera certainement leur lisibilité.

Dans ta page, plus haut vers le début tu emploies 'définition' pour
commenter un 'typedef', est-ce bien conforme à ta définition de
définition ? Il n'y a aucun espace mémoire alloué à un objet, cela ne
peut être une définition au sens strict.

Notons que même Gcc s'est laissé avoir, dans ton exemple donné
précédemment, il dit:

int a;
int a;

int main(void)
{
return 0;
}

Compiling: main.c
main.c:8: warning: redundant redeclaration of 'a'
main.c:7: warning: previous declaration of 'a' was here

alors qu'il aurait du donner un warning pour une redéfinition.

extern int x;
est-ce une déclaration ou une définition ?

C'est un problème ardu !
Pour moi une déclaration (après avoir interverti en ta faveur ma
définition) est caractérisé par le fait qu'elle peut être considérée
comme une instruction au compilateur et ne génère rien par elle_même.
alors qu'une définition génère un code.
Dans le cas de 'extern int x', il n'y a pas de réservation de place pour
x, mais le compilateur doit bien générer une référence externe.

On peut aussi se poser le problème des variables automatiques, sont-elle
réservées à leur définition ?

" What's in a name ? That which we call a rose
By any other name would smell as sweet;"
- W. Shakespeare, Romeo and Juliet, acte II, scène II (qu'on ne dise pas
que j'ai voulu faire croire que c'est de moi :-)

--
Quelle après-midi maussade...



Avatar
Harpo
Emmanuel Delahaye wrote:

typedef int TBOOLEAN;
[...]
extern TBOOLEAN screen_ok;
[...]
TBOOLEAN screen_ok;

La ligne "TBOOLEAN screen_ok;" est probablement une erreur,


Absolument. Il ne devrait pas y avoir de définition d'objet dans un
header. A supprimer. Point.


A un moment j'écrivais des trucs du style :

-----
// truc.h
#ifdef GENERATE
#define EXTERN
#else
#define EXTERN extern
endif

EXTERN int a;
// etc.
-----
Et dans le .c dans lequel devaient être alloués les objets :
-----
// machin.c
#define GENERATE
#include "truc.h"
#endif
-----

J'ai abandonné cette pratique, mais je ne sais plus bien pourquoi, sans
doute simplement parce que je n'utilise pas les extern.


Avatar
Emmanuel Delahaye
http://mapage.noos.fr/emdel/notes.htm#definitions


J'ai donc du confondre comme souvent, mais c'est très confusant.


Oui! Surtout quand on commence à parler de 'tentative definition'...

Comme toujours, ce qui rend l'informatique difficile (et le C en
particulier) c'est l'absence d'une sémantique claire et cohérente...
(pointer vs address, par exemple)

Lorsqu'on ecrit 'typedef int X;', il s'agit d'une déclaration et on
aurait du appeler 'typedef' 'typedecl'.


Ca, c'est encore autre chose. C'est une définition d'alias de type.
'typedef' est correct.

D'ailleurs, je sens que je vais le faire et mettre
#define typedecl typedef
en tête de mes sources... cela augmentera certainement leur lisibilité.


Surtout pas, tu montrerais que tu n'as rien compris, ce qui fait mauvais
effet...

Dans ta page, plus haut vers le début tu emploies 'définition' pour
commenter un 'typedef', est-ce bien conforme à ta définition de
définition ? Il n'y a aucun espace mémoire alloué à un objet, cela ne
peut être une définition au sens strict.


Voir ci-dessus. Mais tu as raison, je vais le préciser dans mon texte.

Notons que même Gcc s'est laissé avoir, dans ton exemple donné
précédemment, il dit:

int a;
int a;

int main(void)
{
return 0;
}

Compiling: main.c
main.c:8: warning: redundant redeclaration of 'a'
main.c:7: warning: previous declaration of 'a' was here

alors qu'il aurait du donner un warning pour une redéfinition.


Exact, mais comme une définition d'objet est aussi une declaration
implicite du même objet,

Ben oui, on est pas obligé d'écrire

int a; /* def */
extern int a; /* decl */

ce n'est pas *complètement* faux...

extern int x;
est-ce une déclaration ou une définition ?

C'est un problème ardu !


C'est une déclaration[ séparée] d'objet (pas d'instanciation de
l'objet), un peu comme un prototype séparé de fonction.

Pour moi une déclaration (après avoir interverti en ta faveur ma
définition) est caractérisé par le fait qu'elle peut être considérée
comme une instruction au compilateur et ne génère rien par elle_même.
alors qu'une définition génère un code.


Absolument. Pour un objet, elle génère une réservation mémoire, et pour
du code, c'est l'implémentation.

Dans le cas de 'extern int x', il n'y a pas de réservation de place pour
x, mais le compilateur doit bien générer une référence externe.


Oui.

On peut aussi se poser le problème des variables automatiques, sont-elle
réservées à leur définition ?


J'ai rien compris, mais oui!

--
A+

Emmanuel Delahaye


1 2 3