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 :

Comment déclarer un tableau avant sa définition ?


Sujet :

C

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 45
    Points : 52
    Points
    52
    Par défaut Comment déclarer un tableau avant sa définition ?
    Bonjour,

    J'ai deux tableaux static.
    Le contenu du 1er tableau fait référence au 2d tableau, et réciproquement (le contenu du 2d tableau fait référence au 1er).
    Je dois donc déclarer ces tableaux avant de pouvoir défini leur contenu.

    Voici mon code (simplifié) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    struct type_fleche  // Flèche de l'automate
    {	int etiquette;		    	// étiquette de la flèche
    	type_fleche *etatSuivant;	// état d'arrivée de la flèche
    };
     
    extern type_fleche etat0[], etat1[];
     
    static type_fleche
    	etat0 [] =
    	 {{ 0, etat1},
    	  { 1, etat0}
         },
    	etat1 [] =
    	 {{ 0, etat1},
    	  { 1, etat1},
    	  { 2, etat0}
    	 };
    Cela compile bien avec VisualC++. Mais avec Mingw, j'obtiens l'erreur suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error: 'etat0' was declared 'extern' and later 'static' [-fpermissive]
    Je reconnais que le compilateur a raison ... mais j'ai essayé plein d'autres solutions, et je n'arrive pas à déclarer un tableau static avant de le définir.

    Quelqu'un pourrait-il m'aider ?

    Merci d'avance

  2. #2
    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
    Il me semble compliqué d'être à la fois externe et static puisque ce sont deux sortes de linkage différents. La solution est sans doute de les déclarer / définir sans les initialiser puis des les initialiser dans une fonction init().

    Néanmoins, je vois que l'erreur est donné par [-fpermissive] et il me semble que cela est une option C++ et non C (https://gcc.gnu.org/onlinedocs/gcc-4...t-Options.html). Chez moi en tout cas, j'ai surtout une erreur pour la définition du type.
    D:\....c|3|error: unknown type name 'type_fleche'|
    Voilà un code qui devrait faire l'affaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include <stdio.h>
     
    struct type_fleche  // Flèche de l'automate
    {
        int etiquette;		    	// étiquette de la flèche
        struct type_fleche *etatSuivant;	// état d'arrivée de la flèche
    };
     
    static struct type_fleche etat0[2], etat1[3];
     
    void init(void)
    {
        etat0 [0] = (struct type_fleche) {0, etat1};
        etat0 [1] = (struct type_fleche) {1, etat0};
     
        etat1 [0] = (struct type_fleche) {0, etat1};
        etat1 [1] = (struct type_fleche) {1, etat1};
        etat1 [2].etiquette = 2;
        etat1 [2].etatSuivant = etat0;
    }
     
    int main(void)
    {
        init();
        printf("etat0 --> %p\n", etat0);
        printf("etat1[2] = %d %p\n", etat1[2].etiquette, etat1[2].etatSuivant);
    }

  3. #3
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 190
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 190
    Points : 17 146
    Points
    17 146
    Par défaut
    Sinon, tu ne les définis pas static.

    Autre solution, les créer statiquement, dans un fichier d'implémentation à part, et proposer des fonctions pour y accéder.
    Comme cela, tu rends la variable elle-même non globale.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    En fait tu dois faire comme cela:

    Déclarer ton tableau en static dans un fichier (là ou tu fais l’instanciation de ton tableau).
    Déclarer ton tableau en extern dans un fichier ou tu ne fais pas l’instanciation, mais pas besoin de le déclarer static.

    Normalement, ça devrait fonctionner.

    (D'ailleurs, je ne suis même pas sur que le déclarer static veuille dire grand chose étant donné que c'est une variable globale ....).
    En général on déclare statique des variable dont le scope n'est pas tout le programme, à savoir:

    Des variable dans une fonction.
    Des variable dans une classe.(pas ton cas comme tu es en C).
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 190
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 190
    Points : 17 146
    Points
    17 146
    Par défaut
    le déclarer static dans un fichier n'est pas l'objectif voulu.

    Je donne des noms pour l'explication: main.c, autre.c, autre.h.
    le code de l'application est réparti entre main.c et autre.c.
    autre.h permet à main.c d'utiliser le reste du code.

    Il convient d'ajouter tableaux.h, et son implémentation tableaux.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //pas de garde, ce ne sont que des déclarations
    extern const int tabs_size;
    extern int tab1[], tab2[];
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #include "tableaux.h"
    const int tabs_size = 4;
    int tab1[] = {0,1,2,3};
    int tab2[] = {0,10,20,30};
    Le code sera compilé en trois unités de compilations: main.o, autre.o et tableaux.o.

    Si tableaux.c déclare les tableaux static, on aura la situation suivante:
    • tableaux.o aura des symboles non liables, les variables statiques
    • main.o et autre.o auront donc des symboles étrangers à résoudre (les variables extern) sans définition.


    éventuellement, on peut rappeler le "extern" dans la définition des variables.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    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
    Citation Envoyé par skeud Voir le message
    En fait tu dois faire comme cela:

    Déclarer ton tableau en static dans un fichier (là ou tu fais l’instanciation de ton tableau).
    Déclarer ton tableau en extern dans un fichier ou tu ne fais pas l’instanciation, mais pas besoin de le déclarer static.
    Il ne doit pas faire comme cela car le linker ne pourra pas utiliser des tableaux statiques pour résoudre un linkage externe.

    Citation Envoyé par skeud Voir le message
    (D'ailleurs, je ne suis même pas sur que le déclarer static veuille dire grand chose étant donné que c'est une variable globale ....).
    En général on déclare statique des variable dont le scope n'est pas tout le programme, à savoir:

    Des variable dans une fonction.
    Des variable dans une classe.(pas ton cas comme tu es en C).
    Elle n'est pas globale, elle est statique à l'unité de compilation. Cela revient à une visibilité private en orienté objet : seules les fonctions de l'unité de compilation peuvent la voir. Si une variable à vocation à être utilisée dans d'autres unités de compilation, l'idée d'un getter et d'un setter suggérée par leternel me semble être la meilleure solution.

  7. #7
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Elle n'est pas globale, elle est statique à l'unité de compilation.
    Qu'entends-tu par unité de compilation? Jamais vu ce terme avant ^^.

    Pour moi quand une variable est en dure dans un .c, elle est accessible depuis partout via le extern. Le extern permet justement de récupéré des variable instanciées dans un autre fichier, d’où l’appellation variable globale.
    De même lors de la compilation, la variable sera instancié dans un .c et aucune autre instance portant le même nom sera acceptée, d’où mon interrogation sur le static, à quoi sert-il si on le met sur une variable?
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  8. #8
    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
    Une unité de compilation est en fait un fichier .c (c'est le terme "scientifique" quand on parle compilation ). C'est important de bien comprendre que la compilation se fait fichier par fichier (unité par unité), de manière séparée. C'est le linker qui ensuite fait "les liens" (comme son nom l'indique si bien) entre les unités de compilation.

    'static' permet justement de ne pas rendre visiblement une variable lors de l'édition des liens. Elle reste interne à l'unité de compilation.

    'extern' permet d'indiquer au compilateur qu'une autre unité de compilation fournira la "vraie" variable et que c'est le linker qui se chargera de la trouver. Si cette variable (au moment du link, on ne parle d'ailleurs plus que de symbole) n'est pas trouvée, alors il y a aura une erreur du type "undefined reference to xxx".

    Par défaut une variable déclarée hors fonction est globale et donc disponible pour le linker pour résoudre les liens ; 'static' réduit sa visibilité et interdit au linker de s'en servir. Tu peux ainsi avoir plusieurs variables statiques avec le même nom, ton linker ne les fait pas entrer en conflit.

  9. #9
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    AAAAAAhhhhhhh oooooookkkkkk. Marrant ça, en fait le static va réduire la porté de la variable, j'aurais plutôt tendance à penser que le static faisait l'inverse ^^. à tors .

    Merci pour cette explication . D'ou le coté: static + extern = pas possible. Je comprends mieux .
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 190
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 190
    Points : 17 146
    Points
    17 146
    Par défaut
    En fait, le terme unité de compilation est tiré de la norme, "compilation unit" et désigne le résultat du préprocesseur sur un fichier source.

    La compilation se fait (en gros) en plusieurs étapes:
    1. préprocesseur: les fichiers en arguments sont parcourus pour supprimer les trigraphes (??! pour |), les '\'en fin de ligne, et évaluer les macros et includes.
      Chaque fichier en argument devient donc un flux de texte intégralement composé de code C sans #machin truc. Cette forme est appelée unité de compilation.
    2. Compilation: chaque unité est compilée indépendamment, produisant autant de "fichiers objets". (les fichiers .o produits par gcc -c)
    3. édition de liens: les fichiers objets sont assemblés en un unique binaire, en reliant les symboles "externes" vers les morceaux qui les matérialisent.


    Un symbole externe est soit une déclaration de fonction (c'est implicite), soit une variable extern.

    static est le contraire de extern, dans le sens qu'il défini un symbole interne à l'unité de compilation.
    Les autres unités ne peuvent pas le trouver, mais il masque un symbole externe du même nom.

    PS: En C++, l'usage du namespace anonyme plutôt que static permet de ne pas masquer completement le symbole externe.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  11. #11
    Membre du Club
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 45
    Points : 52
    Points
    52
    Par défaut
    Merci pour tous vos commentaires.

    J'ai finalement supprimé "static", et ça compile correctement.
    Ce n'est pas exactement ce que je cherchais, mais ça fonctionne, et visiblement ce que je cherchais n'a pas l'air d'être possible (déclarer une variable static avant de la définir).

  12. #12
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 190
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 190
    Points : 17 146
    Points
    17 146
    Par défaut
    Une variable static appartient à une unité de compilation.

    La mettre dans un en-tête provoquera la création de plusieurs variables, une par fichier c incluant l'en-tête.
    Ce n'est certainement pas ce que tu veux.

    Il n'existe pas de déclaration de variable en C.
    La seule chose qui y ressemble c'est une variable externe, dans le sens où, pour le compilateur, la définition est "garantie mais non fournie ici-même".
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

Discussions similaires

  1. Comment déclarer un tableau de tableaux ?
    Par Imène_23 dans le forum Collection et Stream
    Réponses: 7
    Dernier message: 01/08/2011, 17h25
  2. [XL-2007] Comment déclarer un tableau en Public?
    Par mumu27 dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 01/07/2010, 13h57
  3. [AC-2000] Comment déclarer un tableau et son utilisation
    Par AmisNoob dans le forum VBA Access
    Réponses: 3
    Dernier message: 01/12/2009, 19h05
  4. comment déclarer un tableau de pointeur
    Par hanou88 dans le forum C
    Réponses: 2
    Dernier message: 23/01/2009, 01h56
  5. Comment déclarer un tableau de TextBox ?
    Par zappacosta dans le forum Visual C++
    Réponses: 2
    Dernier message: 01/11/2006, 22h51

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