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 :

Utiliser un typedef pour le prototypage de fonctions


Sujet :

C

  1. #1
    Membre actif
    Avatar de TheDrev
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    310
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Novembre 2006
    Messages : 310
    Points : 263
    Points
    263
    Par défaut Utiliser un typedef pour le prototypage de fonctions
    J'ai un souci sur l'emploi des typedef, qui seront utilisés dans des prototypes de fonctions (j'ai résolut le problème en attendant dans le prototype la partie ' struct nom' plutôt que le type definit, c'est plus par curiosité, pour confirmation et en prévision de la reproduction du problème dans un projet plus grand que j ouvre ce thread).

    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
    #ifndef BAR_H
    #define BAR_H
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #include "foo.h"
     
    typedef struct t_bar{
    	int i;
    	int j;
    }bar;
     
     
    void bar_funct(bar *p_bar, foo* p_foo);
     
    #endif
    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
    #ifndef FOO_H
    #define FOO_H
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #include "bar.h"
     
    typedef struct t_foo{
    	int i;
    	int j;
    }foo;
     
     
    void foo_funct(foo *p_foo, bar* p_bar);
     
    #endif
    gcc foo.c bar.c main.c
    In file included from foo.h:7:0,
    from foo.c:1:
    bar.h:16:27: error: expected declaration specifiers or '...' before 'foo'
    In file included from bar.h:7:0,
    from bar.c:1:
    foo.h:16:28: error: expected declaration specifiers or '...' before 'bar'
    In file included from foo.h:7:0,
    from main.c:4:
    bar.h:16:27: error: expected declaration specifiers or '...' before 'foo'



    Cela signifie que typedef ne definit pas completement le type ?

    Je met alors le type complet dans chaque declaration de fonction (et leurs definition dans les fichiers c)

    Pour bar.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void bar_funct(bar *p_bar, struct t_foo* p_foo);
    Pour foo.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void foo_funct(foo *p_foo, struct t_bar* p_bar);
    J'ai maintenant des warnings

    In file included from foo.h:7:0,
    from foo.c:1:
    bar.h:16:35: warning: 'struct t_foo' declared inside parameter list
    bar.h:16:35: warning: its scope is only this definition or declaration, which is
    probably not what you want
    In file included from bar.h:7:0,
    from bar.c:1:
    foo.h:15:35: warning: 'struct t_bar' declared inside parameter list
    foo.h:15:35: warning: its scope is only this definition or declaration, which is
    probably not what you want
    In file included from foo.h:7:0,
    from main.c:4:
    bar.h:16:35: warning: 'struct t_foo' declared inside parameter list
    bar.h:16:35: warning: its scope is only this definition or declaration, which is
    probably not what you want

    Je vais donc définir chaque structure dans chaque fichiers qui l'utilise

    foo.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include "bar.h"
     
    struct t_bar;
     
    typedef struct t_foo{
    	int i;
    	int j;
    }foo;
    bar.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include "foo.h"
     
    struct t_foo;
     
    typedef struct t_bar{
    	int i;
    	int j;
    }bar;
    Et la plus de warnings,
    Questions :
    *est ce la bonne facon de faire ?
    *peut on mettre des typedef dans le prototype d'une fonction comme dans le premier exemple ? Ou faut il prévoir des le debut de l'écriture des headers l'emploi du type complet avec le struct en toute lettre ?
    *N'y a t'il pas un mot cle extern qui peut être utilisé ici pour ce problème ? (je ne me rappel son usage exacte)
    all your base are belong to us.

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Salut

    Je pense que le problème vient du fait que l'un des .h inclue l'autre .h et que les deux .h déclarent deux fonctions utilisant les deux types. Or, forcément, l'un d'eux ne sera pas déclaré avant qu'il soit utilisé dans les paramètre de la fonction.

    Par exemple, si bar.h est inclu en premier, cela donne :

    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
    #ifndef BAR_H
    #define BAR_H
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #include "foo.h"
     
    typedef struct t_bar{
    	int i;
    	int j;
    }bar;
     
    void bar_funct(bar *p_bar, foo* p_foo);
     
    #endif
    Ceci sera transformé en :

    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
    28
    29
    30
    31
    32
    33
    #ifndef BAR_H
    #define BAR_H
     
    #include <stdio.h>
    #include <stdlib.h>
     
    /*#include "foo.h" -> Cette ligne est remplacée par le contenu de foo.h */
    
    #ifndef FOO_H
    #define FOO_H
     
    #include <stdio.h>
    #include <stdlib.h>
     
    /*#include "bar.h" -> cette ligne est zappée car BAR_H est défini */
     
    typedef struct t_foo{
    	int i;
    	int j;
    }foo;
     
    void foo_funct(foo *p_foo, bar* p_bar);
     
    #endif
    
    typedef struct t_bar{
    	int i;
    	int j;
    }bar;
    
    void bar_funct(bar *p_bar, foo* p_foo);
     
    #endif
    Le problème est dans la ligne en rouge : "bar" n'est pas encore défini...

    Maintenant, si c'est l'autre .h est inclu avant, c'est ensuite "foo" qui n'est pas défini...

    Je ne suis pas un expert dans la compilation séparée, mais le fait d'écrire :
    et
    indique au compilateur que ces deux types sont déclarés quelque part, et il ira donc les chercher (au lieu d'afficher plein d'erreurs en disant qu'il ne les connait pas).

  3. #3
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Inclusions croisées, problème de conception non solvable, il faut revoir la conception à ce niveau là pas le choix.


    Et la plus de warnings,
    Ce n'est pas parce qu'il n'y en a pas que c'est forcément juste

    *est ce la bonne facon de faire ?
    Revoir la conception serais mieux, deux objets qui s'utilisent mutellement chacun de leur côté n'est qu'une conception hasardeuse, faut réfléchir plus que cela. Faire un objet qui utilise l'autre ok, voie hiérarchique, faut avoir ceci à l'esprit. Qu'un objet dois savoir ce que l'autre fait oui mais en aucun cas cela doit être réciproque. Tu peux éventuellement avoir deux objets au même niveau de la hiérarchie mais alors tu fera un objet au niveau supérieur qui les utilisera.

    *peut on mettre des typedef dans le prototype d'une fonction comme dans le premier exemple ?
    Oui bien sûr, des fois ce n'est pas recommandé par soucis de compréhension du code mais ca l'allège un peu visuellement.

    *N'y a t'il pas un mot cle extern qui peut être utilisé ici pour ce problème ? (je ne me rappel son usage exacte)
    Rien à voir, le mot-clé extern sert à déclarer une variable statique qui sera visible de tout le programme, à proscrire !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 195
    Points : 115
    Points
    115
    Par défaut
    Ta conception n'est pas hasardeuse. Je ne vois pas pourquoi l'on parle d'objet ici alors que ce sont des fonctions utilisant des structures. Tu peux remedier a ton probleme en faisant un forward declaration c'est a dire que tu declare une de tes structures que tu a besoin avant la fonction. (declarer pas definir) Ensuite tu peux enlever ton inclusion croise.

    Rien à voir, le mot-clé extern sert à déclarer une variable statique qui sera visible de tout le programme, à proscrire !
    Ceci est faux. extern sert a informer l'unite de compilation que la variable ou fonction est definie dans un autre fichier et ne pas se soucier si on ne trouve pas sa declaration au moment de la compilation. Ceci n'est pas a proscrire et est abondament utilise dans la programmation systeme.

  5. #5
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Citation Envoyé par nightwar Voir le message
    Ta conception n'est pas hasardeuse. Je ne vois pas pourquoi l'on parle d'objet ici alors que ce sont des fonctions utilisant des structures. Tu peux remedier a ton probleme en faisant un forward declaration c'est a dire que tu declare une de tes structures que tu a besoin avant la fonction. (declarer pas definir) Ensuite tu peux enlever ton inclusion croise.
    Bin tiens, il n'en serait pas là s'il avait bien réfléchie à la conception de son projet mais je l'avoue, c'est une erreur de débutant. Du moment que tu utilises une structure de données et des fonctions associées on peut utiliser le terme d'objet, peu utilisé en C mais cela ne veut pas dire que ca n'existe pas.

    Je n'entrerais pas plus dans ce débat


    Citation Envoyé par nightwar Voir le message
    Ceci est faux. extern sert a informer l'unite de compilation que la variable ou fonction est definie dans un autre fichier et ne pas se soucier si on ne trouve pas sa declaration au moment de la compilation. Ceci n'est pas a proscrire et est abondament utilise dans la programmation systeme.
    Oui au temps pour moi, je me suis pas bien exprimé
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 195
    Points : 115
    Points
    115
    Par défaut
    oui, il est evident que je ne tombe pas tellement dans ce cas de figure (inclusio croisee) neamnois, dans mes annee de debutant c'est assez frustrant ce genre de chose. Je te rejoins donc sur le fait de revoir la conception. Je proposai uniquement un moyen de resoudre le probleme...

  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
    Pour apporter mon grain de sel sur le terme "objet" en C, il est parfaitement défini par la norme et je ne vois pas d'obstacle à l'utiliser, au contraire :

    3. Terms, definitions, and symbols
    ....
    3.14
    object
    region of data storage in the execution environment, the contents of which can represent values
    Autrement dit, toute variable en C est un objet.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

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

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/03/2010, 11h17
  2. Réponses: 1
    Dernier message: 27/11/2008, 10h55
  3. utilisation d'eval pour une fonction générique
    Par DrDam dans le forum Langage
    Réponses: 5
    Dernier message: 17/09/2008, 12h22
  4. Utiliser les Namespace pour appeler des fonctions
    Par Flamby38 dans le forum VB.NET
    Réponses: 2
    Dernier message: 30/01/2008, 17h27
  5. Utiliser une touche pour appeller une fonction
    Par Hide dans le forum Langage
    Réponses: 2
    Dernier message: 13/10/2005, 16h59

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