Le 23/04/2009 22:29, mpg écrivit :--- BEGIN a.c ---
float var;
--- BEGIN b.c ---
int var = 1;
Je compile tout ça,
On s'arrêtera là si tu veux bien.
Certains compilateurs (c'est la tradition Unix) acceptent cela. Mais pas
tous. D'autres vont gueuler, en particulier certains vont te dire que
«var» est _défini_ à deux endroits distincts, et c'est un endroit de trop.
Utilise gcc -W -Wall : -pedantic ne sert en pratique à rien, et
certaines versions de GCC ont des options dans -W qui ne sont pas dans
-Wall (et de mémoire, cela a une influence sur l'édition des liens).
De fait, extern (devant la déclaration de float var, par exemple) sert à
dire au compilateur « ceci n'est *pas* une définition de var, seulement
une déclaration » (c'est-à-dire la velléité de pouvoir utiliser var un
peu plus loin dans ce source). Le résultat sera donc accepté par les
compilateurs C.
Comme tu le remarques, cela ne résout pas le problème de la disjonction
des types (et les options de GCC ne vont pas aider: l'information du
type de la variable a été perdue lors de la phase compilation, et à la
phase édition-des-liens qui suit, seul moment où on met en relation a et
b, GCC n'a plus la possibilité de s'apercevoir du problème).
Pour résoudre cela, il faut ajouter dans "ab.h"
extern int var;
Et à partir de là, il n'est plus possible de laisser passer l'erreur à
la compilation de b.c.
Déclarer les variables globales dans des fichiers d'en-tête devrait être
obligatoire, en tous cas c'est une bonne habitude de documentation à
prendre (indépendamment du sujet extern).
Le 23/04/2009 22:29, mpg écrivit :
--- BEGIN a.c ---
float var;
--- BEGIN b.c ---
int var = 1;
Je compile tout ça,
On s'arrêtera là si tu veux bien.
Certains compilateurs (c'est la tradition Unix) acceptent cela. Mais pas
tous. D'autres vont gueuler, en particulier certains vont te dire que
«var» est _défini_ à deux endroits distincts, et c'est un endroit de trop.
Utilise gcc -W -Wall : -pedantic ne sert en pratique à rien, et
certaines versions de GCC ont des options dans -W qui ne sont pas dans
-Wall (et de mémoire, cela a une influence sur l'édition des liens).
De fait, extern (devant la déclaration de float var, par exemple) sert à
dire au compilateur « ceci n'est *pas* une définition de var, seulement
une déclaration » (c'est-à-dire la velléité de pouvoir utiliser var un
peu plus loin dans ce source). Le résultat sera donc accepté par les
compilateurs C.
Comme tu le remarques, cela ne résout pas le problème de la disjonction
des types (et les options de GCC ne vont pas aider: l'information du
type de la variable a été perdue lors de la phase compilation, et à la
phase édition-des-liens qui suit, seul moment où on met en relation a et
b, GCC n'a plus la possibilité de s'apercevoir du problème).
Pour résoudre cela, il faut ajouter dans "ab.h"
extern int var;
Et à partir de là, il n'est plus possible de laisser passer l'erreur à
la compilation de b.c.
Déclarer les variables globales dans des fichiers d'en-tête devrait être
obligatoire, en tous cas c'est une bonne habitude de documentation à
prendre (indépendamment du sujet extern).
Le 23/04/2009 22:29, mpg écrivit :--- BEGIN a.c ---
float var;
--- BEGIN b.c ---
int var = 1;
Je compile tout ça,
On s'arrêtera là si tu veux bien.
Certains compilateurs (c'est la tradition Unix) acceptent cela. Mais pas
tous. D'autres vont gueuler, en particulier certains vont te dire que
«var» est _défini_ à deux endroits distincts, et c'est un endroit de trop.
Utilise gcc -W -Wall : -pedantic ne sert en pratique à rien, et
certaines versions de GCC ont des options dans -W qui ne sont pas dans
-Wall (et de mémoire, cela a une influence sur l'édition des liens).
De fait, extern (devant la déclaration de float var, par exemple) sert à
dire au compilateur « ceci n'est *pas* une définition de var, seulement
une déclaration » (c'est-à-dire la velléité de pouvoir utiliser var un
peu plus loin dans ce source). Le résultat sera donc accepté par les
compilateurs C.
Comme tu le remarques, cela ne résout pas le problème de la disjonction
des types (et les options de GCC ne vont pas aider: l'information du
type de la variable a été perdue lors de la phase compilation, et à la
phase édition-des-liens qui suit, seul moment où on met en relation a et
b, GCC n'a plus la possibilité de s'apercevoir du problème).
Pour résoudre cela, il faut ajouter dans "ab.h"
extern int var;
Et à partir de là, il n'est plus possible de laisser passer l'erreur à
la compilation de b.c.
Déclarer les variables globales dans des fichiers d'en-tête devrait être
obligatoire, en tous cas c'est une bonne habitude de documentation à
prendre (indépendamment du sujet extern).
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Dans l'article ,
mpg <mpg+ écrit:Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non. Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Dans l'article <20090424101759.30409.43847.XPN@roth.elzevir.fr>,
mpg <mpg+news@elzevir.fr> écrit:
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non. Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Dans l'article ,
mpg <mpg+ écrit:Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non. Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non.
Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Si var n'est jamais utilisé, ça ne devrait pas foirer (6.9#5).
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non.
Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Si var n'est jamais utilisé, ça ne devrait pas foirer (6.9#5).
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non.
Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Si var n'est jamais utilisé, ça ne devrait pas foirer (6.9#5).
J'ai oublié de préciser que var était utilisé.
J'ai oublié de préciser que var était utilisé.
J'ai oublié de préciser que var était utilisé.
désolé d'être un peu long à la comprenette.
désolé d'être un peu long à la comprenette.
désolé d'être un peu long à la comprenette.
In article <20090427014823$,
Vincent Lefevre wrote:Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Marrant, j'ai l'impression que ca a ete specifie en C99.
J'avais comme souvenir qu'il y avait un bout "implementation dependent"
dans tout ca.
J'ai pas de norme C89 sous la main, mais de memoire
In article <20090427014823$4608@prunille.vinc17.org>,
Vincent Lefevre wrote:
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Marrant, j'ai l'impression que ca a ete specifie en C99.
J'avais comme souvenir qu'il y avait un bout "implementation dependent"
dans tout ca.
J'ai pas de norme C89 sous la main, mais de memoire
In article <20090427014823$,
Vincent Lefevre wrote:Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Marrant, j'ai l'impression que ca a ete specifie en C99.
J'avais comme souvenir qu'il y avait un bout "implementation dependent"
dans tout ca.
J'ai pas de norme C89 sous la main, mais de memoire
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
À noter que le linkeur de Mac OS X [...] est buggé:
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
À noter que le linkeur de Mac OS X [...] est buggé:
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
À noter que le linkeur de Mac OS X [...] est buggé:
Dans l'article ,
mpg <mpg+ écrit:Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non. Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
À noter que le linkeur de Mac OS X (10.5.x uniquement il me semble[*])
est buggé: quand il y a une tentative, mais pas de définition externe,
le linkeur considère que l'identifieur n'est pas défini (il ne respecte
pas 6.9.2#2), et le link échoue si l'identifieur est utilisé.
[*] Alors que MPFR fonctionnait bien avec 10.4.x, on a eu un rapport
de bug par un utilisateur de 10.5.x. J'ai alors demandé de retester
avec des définitions au lieu de tentatives, et le problème a disparu!
Comme les tentatives (au lieu de définitions) n'étaient pas vraiment
nécessaires, on les a remplacées par des définitions.D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Si var n'est jamais utilisé, ça ne devrait pas foirer (6.9#5).
Dans l'article <20090424101759.30409.43847.XPN@roth.elzevir.fr>,
mpg <mpg+news@elzevir.fr> écrit:
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non. Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
À noter que le linkeur de Mac OS X (10.5.x uniquement il me semble[*])
est buggé: quand il y a une tentative, mais pas de définition externe,
le linkeur considère que l'identifieur n'est pas défini (il ne respecte
pas 6.9.2#2), et le link échoue si l'identifieur est utilisé.
[*] Alors que MPFR fonctionnait bien avec 10.4.x, on a eu un rapport
de bug par un utilisateur de 10.5.x. J'ai alors demandé de retester
avec des définitions au lieu de tentatives, et le problème a disparu!
Comme les tentatives (au lieu de définitions) n'étaient pas vraiment
nécessaires, on les a remplacées par des définitions.
D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Si var n'est jamais utilisé, ça ne devrait pas foirer (6.9#5).
Dans l'article ,
mpg <mpg+ écrit:Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non. Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
À noter que le linkeur de Mac OS X (10.5.x uniquement il me semble[*])
est buggé: quand il y a une tentative, mais pas de définition externe,
le linkeur considère que l'identifieur n'est pas défini (il ne respecte
pas 6.9.2#2), et le link échoue si l'identifieur est utilisé.
[*] Alors que MPFR fonctionnait bien avec 10.4.x, on a eu un rapport
de bug par un utilisateur de 10.5.x. J'ai alors demandé de retester
avec des définitions au lieu de tentatives, et le problème a disparu!
Comme les tentatives (au lieu de définitions) n'étaient pas vraiment
nécessaires, on les a remplacées par des définitions.D'ailleurs, si j'essaie de compiler un programme avec deux fichiers et
que je mets 'extern int var;' dans les deux sans qu'aucun ne contienne
de définition de var, alors effectivement ça foire en me disant que
"undefined reference to `var'" à l'édition de liens.
Si var n'est jamais utilisé, ça ne devrait pas foirer (6.9#5).
Vincent Lefevre scripsit:Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non.
Bon, merci de ne pas me laisser dans l'erreur.Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
Donc si je comprends bien, les déclarations de fonctions, ainsi que
celles de variables dont la porté est le fichier ont un extern implicite
sauf si on dit explicitement autre chose."extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Bon, je crois que mon problème (un de mes problèmes) est que je ne
saisis pas la différence entre déclaration et définition, à la fois au
niveau syntaxique et au niveau sémantique, en ce qui concerne les
variables.
Pour l'instant, j'ai tendance à croire que déclarer un identifiant, ça
revient à dire au compilateur « ceci est l'indentifiant d'un objet de
tel type, ne gueule pas si tu me vois utiliser cet identifiant
conformément à ce type » alors que la définition, c'est ce qui fait que
le compilateur va effectivement réserver un place en mémoire pour
l'objet. Suis-je à côté de la plaque sur ce point ?
Par contre, niveau syntaxique, j'ai beaucoup de mal à voir ce qui
différencie les deux. J'ai l'impression qu'une déclaration qui comporte
aussi une initialisation est de fait une définition.
Pour le reste,
visiblement le compilateur ne se décide pas au moment où il lit la
déclaration pour savoir si c'est aussi une définition : il attend la fin
de l'unité de compilation (le fichier ?)
pour fusionner les déclarations
et en faire quelque chose ? Quoiqu'en lisant le message de Marc, il
semble qu'il y a aussi l'éditeur de lien qui fusionne les définitions
(ou les tentatives)...
Bon, je vais essayer d'aller fouiller dans la norme pour voir si j'y
trouve une définition des expressions suivantes :
- déclaration
- définition
- « tentative definition »
Mais la dernière fois que j'ai essayé de chercher des trucs dans la
norme, j'étais un peu perdu.
Vincent Lefevre scripsit:
Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non.
Bon, merci de ne pas me laisser dans l'erreur.
Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
Donc si je comprends bien, les déclarations de fonctions, ainsi que
celles de variables dont la porté est le fichier ont un extern implicite
sauf si on dit explicitement autre chose.
"extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Bon, je crois que mon problème (un de mes problèmes) est que je ne
saisis pas la différence entre déclaration et définition, à la fois au
niveau syntaxique et au niveau sémantique, en ce qui concerne les
variables.
Pour l'instant, j'ai tendance à croire que déclarer un identifiant, ça
revient à dire au compilateur « ceci est l'indentifiant d'un objet de
tel type, ne gueule pas si tu me vois utiliser cet identifiant
conformément à ce type » alors que la définition, c'est ce qui fait que
le compilateur va effectivement réserver un place en mémoire pour
l'objet. Suis-je à côté de la plaque sur ce point ?
Par contre, niveau syntaxique, j'ai beaucoup de mal à voir ce qui
différencie les deux. J'ai l'impression qu'une déclaration qui comporte
aussi une initialisation est de fait une définition.
Pour le reste,
visiblement le compilateur ne se décide pas au moment où il lit la
déclaration pour savoir si c'est aussi une définition : il attend la fin
de l'unité de compilation (le fichier ?)
pour fusionner les déclarations
et en faire quelque chose ? Quoiqu'en lisant le message de Marc, il
semble qu'il y a aussi l'éditeur de lien qui fusionne les définitions
(ou les tentatives)...
Bon, je vais essayer d'aller fouiller dans la norme pour voir si j'y
trouve une définition des expressions suivantes :
- déclaration
- définition
- « tentative definition »
Mais la dernière fois que j'ai essayé de chercher des trucs dans la
norme, j'étais un peu perdu.
Vincent Lefevre scripsit:Merci. J'en a profité pour aller lire aussi #definitions. Du coup je
crois avoir compris qu'en fait 'int x;' est une définition de x qui vaut
aussi déclaration, alors que 'extern int x;' est une déclaration mais
pas une définition, c'est-à-dire que le compilateur ne va pas réserver
d'espace mémoire pour x, comptant trouver une définition de x plus tard
ailleurs.
Non.
Bon, merci de ne pas me laisser dans l'erreur.Tout d'abord, le extern est souvent facultatif. 6.2.2#5:
If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if
it were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
Donc si je comprends bien, les déclarations de fonctions, ainsi que
celles de variables dont la porté est le fichier ont un extern implicite
sauf si on dit explicitement autre chose."extern int x;" est une déclaration uniquement. "int x;" est une
déclaration, mais aussi une tentative de définition. 6.9.2#2:
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or
with the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains
no external definition for that identifier, then the behavior is
exactly as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of the
translation unit, with an initializer equal to 0.
Donc tu peux très bien mettre plusieurs "int x;" sans extern, ce
qui aurait été impossible si c'était une définition (puisqu'il ne
peut y avoir qu'au plus une définition).
Bon, je crois que mon problème (un de mes problèmes) est que je ne
saisis pas la différence entre déclaration et définition, à la fois au
niveau syntaxique et au niveau sémantique, en ce qui concerne les
variables.
Pour l'instant, j'ai tendance à croire que déclarer un identifiant, ça
revient à dire au compilateur « ceci est l'indentifiant d'un objet de
tel type, ne gueule pas si tu me vois utiliser cet identifiant
conformément à ce type » alors que la définition, c'est ce qui fait que
le compilateur va effectivement réserver un place en mémoire pour
l'objet. Suis-je à côté de la plaque sur ce point ?
Par contre, niveau syntaxique, j'ai beaucoup de mal à voir ce qui
différencie les deux. J'ai l'impression qu'une déclaration qui comporte
aussi une initialisation est de fait une définition.
Pour le reste,
visiblement le compilateur ne se décide pas au moment où il lit la
déclaration pour savoir si c'est aussi une définition : il attend la fin
de l'unité de compilation (le fichier ?)
pour fusionner les déclarations
et en faire quelque chose ? Quoiqu'en lisant le message de Marc, il
semble qu'il y a aussi l'éditeur de lien qui fusionne les définitions
(ou les tentatives)...
Bon, je vais essayer d'aller fouiller dans la norme pour voir si j'y
trouve une définition des expressions suivantes :
- déclaration
- définition
- « tentative definition »
Mais la dernière fois que j'ai essayé de chercher des trucs dans la
norme, j'étais un peu perdu.