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 :

Redéfinition de variables


Sujet :

C

  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut Redéfinition de variables
    Bonjour,

    En lisant compilant un code lu sur ce forum, j'ai été étonné que le code suivant compile sans erreur ni warning, et que la sortie en console soit correcte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
     
    int a;
    int a;
     
    int main(void)
    {
        a = 10;
        printf("a = %d", a);
        return 0;
    }


    Celui-ci non plus ne pose pas de problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
     
    int a;
    int a=1;
     
    int main(void)
    {
        printf("a = %d", a);
        return 0;
    }


    En revanche, celui-ci produit des erreurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
     
    int a=1;
    int a=1;
     
    int main(void)
    {
        int b;
        int b; // ici, je m'y attendais
        printf("a = %d", a);
        return 0;
    }
    Sortie de compilation :
    d:\Documents and Settings\pgradot\Mes documents\Tools SD\A voir\test.c|4|error: redefinition of 'a'|
    d:\Documents and Settings\pgradot\Mes documents\Tools SD\A voir\test.c|3|note: previous definition of 'a' was here|
    d:\Documents and Settings\pgradot\Mes documents\Tools SD\A voir\test.c||In function 'main'
    d:\Documents and Settings\pgradot\Mes documents\Tools SD\A voir\test.c|9|error: redeclaration of 'b' with no linkage|
    d:\Documents and Settings\pgradot\Mes documents\Tools SD\A voir\test.c|8|note: previous declaration of 'b' was here|
    d:\Documents and Settings\pgradot\Mes documents\Tools SD\A voir\test.c|9|warning: unused variable 'b'|
    ||=== Build finished: 2 errors, 1 warnings ===|


    Pourquoi est-ce que je n'ai pas d'erreur pour les variables globales avec les 2 premiers codes ? Je précise que je compile avec CodeBlocks sous XP avec -Wall et -Wextra.

    Merci !

  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
    Le compilateur fait parfois quelques optimisations.

    Je pense que lorsqu'on manipule des variables globales, il considère que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int a; int a; //revient à faire uniquement int a; car le 2ème a écrase le 1er a
    int a;int a=1; //revient à faire uniquement int a=1; idem
    int a=1; int a=1; //ne va pas car on va perdre une information si le 2ème a écrase le premier, on perd la valeur contenue dans a
    De toute façon, la question ne devrait pas se poser : on ne fait pas de variables globales et voila

  3. #3
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    C'est une hypothèse plutôt bonne, mais pourquoi ne pas faire la même chose sur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        int b;
        int b; // ici, je m'y attendais
    dans le main() ?

  4. #4
    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
    Hors du main et des fonctions, le compilateur choisit l'ordre "d'exécution" ou plutôt d'initialisation des variables.

    Dans le main et les fonctions, c'est plus compliqué, on peut faire des sauts (goto, siglongjmp), un signal peut se produire etc...

    Donc s'il a deux lignes "int a", s'il veut optimiser et n'en mettre qu'une seule, où mettre le "int a" ? A la ligne du premier "int a" ou à la ligne du deuxième "int a"?
    Sachant que ceci pourra avoir une incidence sur le code final.


    Après ce n'est qu'une hypothèse.

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    Tu te défens bien en bonnes hypothèses, tu sais

  6. #6
    Membre éclairé
    Avatar de bpy1401
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2003
    Messages
    471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2003
    Messages : 471
    Points : 831
    Points
    831
    Par défaut
    Bonjour à tous

    D'après ce que je vois au chapitre 6.5 de la norme C Ansi.

    All declarations in the same scope that refer to the same object or function shall specify compatible types.
    j'en déduis que vous pouvez déclarer plusieurs fois le même objet si il est de type compatible, donc le premier est correct. Mais cela ne ne colle pas avec les autres cas.
    Page sur Developpez : http://pbriand.developpez.com

  7. #7
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Ces situations sont décrites par la norme ici : (n1256 ) 6.2.2 Linkages of identifiers
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  8. #8
    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
    Pour éviter de devoir parcourir toute la norme :

    6.2.2 Linkages of identifiers
    1 An identifier declared in different scopes or in the same scope more than once can be
    made to refer to the same object or function by a process called linkage.21) There are
    three kinds of linkage: external, internal, and none.

    2 In the set of translation units and libraries that constitutes an entire program, each
    declaration of a particular identifier with external linkage denotes the same object or
    function. Within one translation unit, each declaration of an identifier with internal
    linkage denotes the same object or function. Each declaration of an identifier with no
    linkage denotes a unique entity.

    3 If the declaration of a file scope identifier for an object or a function contains the storageclass
    specifier static, the identifier has internal linkage.22)

    4 For an identifier declared with the storage-class specifier extern in a scope in which aprior declaration of that identifier is visible,23) if the prior declaration specifies internal or
    external linkage, the linkage of the identifier at the later declaration is the same as the
    linkage specified at the prior declaration. If no prior declaration is visible, or if the prior
    declaration specifies no linkage, then the identifier has external linkage.

    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.

    6 The following identifiers have no linkage: an identifier declared to be anything other than
    an object or a function; an identifier declared to be a function parameter; a block scope
    identifier for an object declared without the storage-class specifier extern.

    7 If, within a translation unit, the same identifier appears with both internal and external
    linkage, the behavior is undefined.
    Forward references: declarations (Forward references: declarations (6.7), expressions (6.5), external definitions (6.9),
    statements (6.8).

    23) As specified in 6.2.1, the later declaration might hide the prior declaration.
    Ne parlant pas très bien anglais je n'ai pas tout compris

    Mais je suppose que c'est le même procédé utilisé pour :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    struct a;
     
    struct
    {
          struct a * a;
    }b;
     
    struct
    {
          struct b * b;
    }a;

  9. #9
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    Merci Diogene pour la référence. C'est subtil, faut prendre son temps pour comprendre. Je pense que le point 2 suffit à expliquer le problème.
    • Les variables globales sont avec linkage externe (en accord avec le point 5), donc les deux déclarations (ou une déclaration + une définition) dénotent du même objet. Pas de soucis pour le compilateur.
      Si on met de 2 définitions, effectivement il y a là une redéfinition de la variable (le message d'erreur que j'ai posté dans #1 ne parle pas de redéclaration, mais bien uniquement d'une redéfinition de a).
    • Les variables locales au main sont sans linkage (le compilateur le précise) et chaque déclaration dénote un objet différent. Il y a donc bien une redéclaration de b dans le main. Le compilateur y voit 2 objets avec le même nom.


    La remarque 23 ne parle pas plutôt de ce cas ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include<stdio.h>
    #include<stdlib.h>
    int a = 42;
    int main(void)
    {
        int a = 666; /* Cette instruction masque la definition precedente,
                    On la commente pour afficher 42. */
        printf("a = %d\n", a);
        return 0;
    }
    Elle ferait référence au point 4 du paragraphe 6.2.1 :
    Within the inner scope, the
    identifier designates the entity declared in the inner scope; the entity declared in the outer
    scope is hidden (and not visible) within the inner scope.
    Enfin, c'est ce que je pense...

    Neckara, il y a t-il une utilité au code que tu as montré ou est-ce juste un code qui fait "n'importe quoi" ?


    PS : un lien utile http://publications.gbdirect.co.uk/c...4/linkage.html

    PS2 : quelqu'un connait "the C book" ? C'est un livre qui fait référence ? On peut faire confiance à son contenu ?

  10. #10
    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
    @Bktero : Merci d'avoir traduit le passage en anglais, je n'avais pas tout saisi les raisons^^

    Neckara, il y a t-il une utilité au code que tu as montré ou est-ce juste un code qui fait "n'importe quoi" ?
    Je vais essayer de trouver un exemple concret :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    struct Table
    {
          struct Couvert * liste; //liste des couverts posé sur la table
    };
     
    struct Couvert
    {
           struct Table * table; //table sur laquelle le couvert est posé
    };
    Mais pour déclarer une Table, on doit d'abord déclarer Couvert puisque Table possède un pointeur sur Couvert. Idem avec Couvert qui a un pointeurs sur Table.

    C'est le serpent qui se mort la queue.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    struct Couvert; //il suffit de rajouter cette ligne pour que cela marche.
     
    struct Table
    {
          struct Couvert * liste; //liste des couverts posé sur la table
    };
     
    struct Couvert
    {
           struct Table * table; //table sur laquelle le couvert est posé
    };
    Je pense donc que ce mécanisme permet principalement de résoudre le problème du serpent qui se mort la queue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 02/09/2010, 13h20
  2. redéfinition de variable d'instance
    Par swinger45 dans le forum Langage
    Réponses: 8
    Dernier message: 27/09/2006, 19h34
  3. Procédure avec un nombre variable d'arguments
    Par charly dans le forum Langage
    Réponses: 15
    Dernier message: 21/06/2002, 12h08
  4. Réponses: 4
    Dernier message: 05/06/2002, 15h35
  5. les variables globales static
    Par gRRosminet dans le forum C
    Réponses: 8
    Dernier message: 27/04/2002, 09h34

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