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 :

Prototype de fonction inline


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mars 2013
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mars 2013
    Messages : 31
    Par défaut Prototype de fonction inline
    Bonjour,

    Voilà, je me posais une petite question sur l'utilité d'un prototype d'une fonction inline.

    J'ai lu dans la FAQ que la fonction inline doit etre définie dans le .h. Elle est ensuite appelée dans les fichiers .cpp dans lesquels on en a besoin.
    Mais le prototype, est-il utile?

    Pour une fonction "classique", je voyais l'utilité de mettre le prototype de la fonction dans le .h: On indiquait au compilateur que quelque part dans le code, on va peut etre rencontré une fonction "toto", mais pas de panique, elle sera définie quelque part.

    Mais là, on a directement la définition de la fonction inline dans le .h. Quel interet de mettre alors un prototype...?

    PS: J'ai fait le test: sans prototype, j'obtiens une erreur à l'édition de lien...

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    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 026
    Par défaut
    Bonjour,

    Sans code, cela est difficile de voir ce qu'il ne va pas.

    Lorsque tu définis une fonction, tu (re)déclare aussi son prototype.
    Pour une fonction inline, on mettra dans le .h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline void foo(void)
    {
              //fait ce que tu veux
    }

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, il faut surtout voir de quoi l'on parle car il est possible d'avoir des fonctions libres et des foncions membres.

    Et comme il est tout aussi possible d'appeler des fonctions membre depuis une fonction libre et d'appeler une fonction libre depuis une fonction membre, et que, de plus, il est possible de déporter la définition de fonctions membre en dehors de la classe ou de la structure à laquelle elles appartiennent, ca fait pas mal de possibilités (que je vais essayer de parcourir avec toi )

    Pour une fonction libre inline, tu peux en effet fournir directement son implémentation, sauf si tu as une autre définition de fonction qui apparait AVANT ta fonction et qui l'utilise.

    A ce moment là, il y a lieu de réfléchir un tout petit peu

    En effet, le compilateur parcoure le code source exactement de la manière dont tu lis un livre et, tout comme tu ne sais pas dire ce qui se passe à la page 11 quand tu es à la page 10, le compilateur ne connait à la ligne 10 que... ce qu'il a déjà rencontré.

    Mettons que tu aies deux fonctions inline : foo et bar, et que bar doive faire appel à foo.

    Le compilateur sera content s'il a rencontré foo avant de rencontrer son appel dans bar, et donc avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    /* inline */ void foo(){
    /*...*/
    }
    /* inline */ void bar(){
    foo();
    }
    alors qu'il t'enverra sur les roses avec le code suivant (si tu n'as pas déclaré le prototype de foo)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    /* inline */ void bar(){
    foo();
    }
    /* inline */ void foo(){
    /*...*/
    }
    Le fait que la fonction soit inlinée ou non ne change strictement rien

    Et si foo fait appel à bar et que bar fait appel à foo (c'est alors un certain type de récursivité ), il est clair que tu n'auras pas le choix : il faudra fatalement fournir le prototype de la deuxième fonction avant d'essayer de donner l'implémentation de la première, et ce, que ta (tes) fonctions soi(ent) déclarée(s) inline ou non.

    Dans le cas où tu as une fonction membre, il faut savoir que:
    1. toute fonction définie directement dans le corps de la classe ou de la structure est implicitement déclarée inline
    2. le compilateur analyse l'ensemble de la composition de la classe ou de la structure avant de regarder à l'implémentation des fonctions, ce qui facilite un peu les chose
    Ainsi, les fonctions foo et bar sont implicitement déclarées inline dans la classe suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MaClasse{
        public:
        void foo(){/* ... */}
        void bar(){/* ... */}
    };
    Mais, comme elles sont membres de la même classe ne se plaindra pas si foo appelle bar et / ou si bar appelle foo.

    Par contre, si tu veux déporter les fonctions foo et bar sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MaClasse{
        public:
        void foo();
        void bar();
    };
    void MaClasse::foo(){
    /* ... */
    }
    void MaClasse::bar(){
    /* ... */
    }
    et que tu veux qu'elles soient inlinées, il faudra
    1. fournir leur prototype dans MaClasse
    2. les déclarer explicitement inline
    Encore une fois, le fait que l'une fasse éventuellement appel à l'autre n'aura pas d'incidence

    Enfin, il reste le problème (par chance fort similaire) d'une fonction libre qui fait appel à une fonction membre et vice versa.

    Et là, on en revient toujours au même point : le compilateur ne connait que ce qu'il a déjà rencontré dans les lignes précédentes

    Si tu veux qu'une fonction libre fasse appel à une fonction membre, il faut... que le compilateur ait déjà rencontré la définition complete de la classe ou de la structure dont la fonction membre est issue.

    Le simple fait d'avoir une déclaration anticipée ne suffit alors plus.

    De même, si tu veux appeler une fonction libre depuis une fonction membre, il faudra que le compilateur ait, au minimum, déjà rencontré le prototype de la fonction libre lorsqu'elle sera appelée dans la fonction membre.

    Ainsi, le compilateur t'enverra sur les roses s'il rencontre un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MaClasse{
        public:
        void foo(){bar();} // implicitement inline
    };
    inline void bar(){
    /*...*/
    }
    tout comme il t'enverra sur les roses s'il rencontre un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MaClasse; // seul moyen pour que le prototype de foo passe, et encore, 
                    // sous conditions
    inline void bar(MaClasse /* const */ & obj){
    obj.foo();
    }
    class MaClasse{
        public:
        void foo(){/*...*/} // implicitement inline
    };
    Et bien sur, si foo appelle bar et que bar appelle foo, tu n'es pas sorti de l'auberge

    Enfin, si tu déportes l'implémentation de foo, il faudra encore réfléchir à l'ordre dans lequel tu définis foo et bar, car le compilateur refusera un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MaClasse{
        public:
        inline foo(); // explicitement inline
    }
    void MaClasse::foo(){
        bar(); // KO : le compilateur ne connait pas encore bar
    }
    void bar(MaClasse /* const &*/ obj){
        obj.foo(); //OK le compilateur connait MaClasse::foo()
    }
    alors qu'il acceptera un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MaClasse{
        public:
        inline foo(); // explicitement inline
    }
    void bar(MaClasse /* const &*/ obj){
        obj.foo(); //OK le compilateur connait MaClasse::foo()
    }
    void MaClasse::foo(){
        bar(); // OK : le compilateur connait bar()
    }
    Bref...

    Tout cela pour dire que tu peux, effectivement, envisager de ne pas fournir de prototype seul sur les fonctions inline, mais qu'il faudra alors être particulièrement attentif à l'ordre dans lequel tu les écrit, surtout si l'une d'elle doit faire appel à une autre
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre averti
    Inscrit en
    Mars 2013
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mars 2013
    Messages : 31
    Par défaut
    Bonjour à vous deux et merci de vous attarder sur mon problème.

    Je pense que j'avais relativement bien compris ce que tu expliques Koala. Mais je n'arrive pas à comprendre ce qui se passe dans mon cas...

    Tu as raison Neckara, je vais mettre un peu de code pour expliquer mon problème. Je pensais que ma question était relativement générale pour ne pas avoir besoin de s'attarder sur mon cas, mais visiblement non

    Je vous propose donc deux fichiers: toto.cpp et toto.h

    toto.h contient plusieurs choses, dont la définition de la fonction inline qui m'intéresse:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // patati patata
     
    inline double carre(double a, double b)
    {
    return a*a+b*b; // J'ai écris n'importe quoi ici
    }
     
    // patati patata
    toto.cpp contient lui plusieurs définition de fonction dont une en particulier

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // patati patata
     
    void Truc(...)
    {
    double carre(double a, double b); //qui ressemble à un prototype (mais sans "inline")
    double h,f,g;
    // patati patata
    h=carre(f,g);
    // patati patata
     
    }
     
    // patati patata

    Avec ce code, ça ne fonctionne pas (ni même lorsque je rajoute "inline" dans le prototype de la fonction): "undefined reference to carre".

    Pour tester, j'ai simplement déplacé le prototype de ma fonction (en ajoutant le mot clé inline cette fois) juste au dessus de la définition de ma fonction inline dans le .h et non plus dans le .cpp comme c'était le cas avant.

    toto.h devient alors:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // patati patata
     
    inline double carre(double a, double b);
    inline double carre(double a, double b)
    {
    return a*a+b*b; // J'ai écris n'importe quoi ici
    }
     
    // patati patata
    Et là suprise, ça fonctionne...
    Je ne comprend pas pourquoi. Autant je comprend l'utilité d'un prototype quand il est possible que le compilateur rencontre l'appel à une fonction avant la déclaration de cette fonction.
    Mais avec les fonction inline, la déclaration est dans le .h. Quoiqu'il arrive, il va donc rencontrer la déclaration avant l'appel (dans mon cas en tout cas) et je ne vois donc pas l'utilité de lui rajouter le prototype...

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Josiane22 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // patati patata
     
    void Truc(...)
    {
    double carre(double a, double b); //qui ressemble à un prototype (mais sans "inline")
    double h,f,g;
    // patati patata
    h=carre(f,g);
    // patati patata
     
    }
     
    // patati patata
    Attention, ce code là ne fait absolument pas ce que tu crois!!!

    Il déclare une fonction nommée carre qui prend deux double comme paramètres et renvoyant un double...

    Si tu veux appeler ta fonction, il faut... déclarer une variable qui sera initialisée avec le retour de la fonction sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    // patati patata
     
    void Truc(...)
    {
    double x/* ou truc, ou meme carre */ =carre(double a, double b); //qui ressemble à un prototype (mais sans "inline")
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre averti
    Inscrit en
    Mars 2013
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mars 2013
    Messages : 31
    Par défaut
    Désolé mais je ne comprends pas ce que tu veux me dire...

    est bien remplacé par ce qu'il y a dans ma fonction inline non? Donc h vaut bien ensuite f*f+g*g?

    Pour ce qui est de la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double carre(double a, double b);
    , on est d'accord que ce n'est que le prototype de la fonction inline non?

    PS: Je précise que le problème que j'ai c'est lorsque je compile en mode DEBUG. Avec une compilation "normale", tout se passe bien...
    De plus, le problème survient à l'édition de lien.

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

Discussions similaires

  1. [POO] Prototypes de fonctions et IE
    Par T.NightGlow dans le forum Bibliothèques & Frameworks
    Réponses: 9
    Dernier message: 15/01/2008, 16h50
  2. Fonctions inline
    Par vdumont dans le forum C++
    Réponses: 5
    Dernier message: 12/05/2006, 19h40
  3. .net prototype de fonction
    Par stgi02 dans le forum MFC
    Réponses: 1
    Dernier message: 13/04/2006, 22h41
  4. prototype de fonction ?
    Par salseropom dans le forum C
    Réponses: 3
    Dernier message: 07/04/2006, 10h01
  5. Fonctions inlines et fichiers .lib
    Par michhh dans le forum C++
    Réponses: 3
    Dernier message: 05/07/2005, 03h09

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