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

Langage C++ Discussion :

Est-il possible de faire un inline partiel d'une fonction ?


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par défaut Est-il possible de faire un inline partiel d'une fonction ?
    Bonjour, je viens de me poser une question simple :

    Est-il possible de faire un inline partiel d'une fonction ?

    J'aimerais savoir s'il est possible lors de l'appel d'une fonction de choisir si on veut que le compilateur copie le code ou alors appelle la fonction.
    Car j'ai une fonction dans ma librairie que j'appelle de l'extérieur donc elle ne doit pas être inline de ce côté mais je l'appelle beaucoup en interne dans ma boucle principale dont j'essaie de réduire le temps de calcul.

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Normalement le compilo est capable de décider cela.

    Sinon, au pire tu la déclares inline et tu exposes un wrapper...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    Par défaut
    Le langage n'interdit pas qu'une fonction de l'API d'une bibliothèque soit inline.

    Cela dit, est-ce certain que c'est le temps d'appel de cettte fonction qui coûte le plus cher dans ta boucle?

  4. #4
    Membre très actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par défaut
    Merci de vos réponse.

    Tout d'abord, je ne sais pas ce qu'est un wrapper .
    Et le inline fonctionne aussi si la librairie est en .dll ou .a? N'y a-t'il pas des cas ou cela poserais des problèmes?
    Sinon non, je ne pense pas que ce soit l'appel de ma fonction qui ralentisse le temps exécution, je me posais juste la question car je suis en train de programmer en C pour GPU et j'ai besoin que mon code soit très rapide.

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Tu peux laisser le compilateur décider pour toi, il aura raison dans un bon 95% des cas.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message
    Tout d'abord, je ne sais pas ce qu'est un wrapper
    Wikipédia anglais donne une décision très claire :
    A wrapper function is a subroutine in a software library or a computer program whose main purpose is to call a second subroutine or a system call with little or no additional computation.
    Voici un exemple simpliste de code :
    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
    #include <iostream>
    using namespace std;
     
    void real_function()
    {
        cout << "real_function" << endl;
    }
     
    void wrapper()
    {
        real_function();
    }
     
    int main()
    {
        wrapper();
    }
    Le même article Wikipédia donne des raisons d'utiliser des wrappers. Souvent, il s'agit de simplifier des appels ou de faire des adaptations de prototypes de fonctions. Un exemple concret peut-être la création de pthread. Quand tu crées un thread, tu dois lui passer un pointeur sur fonction avec un prototype comme celui-ci : void * (* start_routine) (void *). Comme ta fonction est peut-être void do_job()void, tu vas vouloir écrire un wrapper avec le bon prototype. Tu passeras un pointeur vers ton wrapper à pthread_create() et dans ce wrapper tu feras justement un appel à do_job() dedans.

  7. #7
    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,

    IMHO, l'inlining d'une fonction vient en numéro 257 dans l'ordre des priorités pour obtenir de meilleures performances. C'est te dire que c'est de la micro optimisation, et qu'il y a sans doute 256 choses bien plus intéressantes à faire avant d'y penser.

    En effet, le processus mis en oeuvre pour faire appel à une fonction non inline se réduit à trois (allez, peut être quatre) instruction processeur; auxquelles il faut (ne les oublions pas) sans doute ajouter un nombre équivalent d'instructions pour pouvoir reprendre l'exécution de la fonction appelante.

    En termes de temps d'exécution, cela se traduit vraiment par peanuts au vu des performances des processeurs acutels (y compris si on regarde du coté des smartphones!). Bien avant d'en arriver à un point où ce genre d'optimisation produira un effet "palpable", il y a donc pas mal de choses susceptibles d'améliorer les performances de manière bien plus significatives, par exemple:
    • éviter les copies inutiles
    • éviter les allocations de mémoire inutiles
    • améliorer tes algorithmes en évitant parcourir une boucle qui provoque de nombreux calculs
    • améliorer tes algorithmes en évitant de calculer des valeurs qui n'ont aucune chance d'aboutir
    • améliorer tes algorithmes en préférant une complexité moindre (en O(N) au lieu d'en O(N2), en O(log(N)) au lieu d'en O(N), en O(1) au lieu d'en O(log(N)), ...)
    • améliorer tes structures afin de pouvoir améliorer la complexité de tes algorithmes
    • améliorer l'organisation de tes données afin d'éviter les cache misses
    • ...


    (ce n'est pas forcément dans l'ordre, et surement pas exhaustif )

    De plus, il faut bien te rendre compte que l'inlining n'est pas sans "effets secondaires indésirables". Le plus important étant une augmentation potentiellement très grande de la taille de ton binaire.

    Un autre aspect important à prendre en compte étant que la définition (l'implémentation pour être précis) d'une fonction inline doit être accessible à toutes les unités de compilation (tous les fichier *.cpp) dans laquelle elle est appelée sous sa forme inline. Et ca, ca peut rapidement devenir problématique, surtout si tu souhaite placer un wrapper qui te permettra d'y accéder de manière classique. Un petit exemple (tiré de l'exemple de Bktero) pour te faire comprendre:

    Imaginons un cas simple pour commencer: la fonction inline ne doit être appelée que dans une seule unité de compilation. Nous pourrions exposer le wrapper au travers de la bibliothèque dynamique sous la forme d'un fichier d'en-tête proche de

    wrapper.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #ifndef WRAPPER_HPP_INCLUDED
    #define WRAPPER_HPP_INCLUDED
    void MY_LIB_API wrapper()
    #endif
    et avoir une unité de compilation proche de
    compile_unit.hpp
    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
    #include <wrapper.hpp>
    /* la fonction que l'on veut inliner */
    inliine function(){
        /* blabla */
    }
    /* la fonction wrapper */
    void wrapper(){
        function();
    }
     
    /* d'autres fonctions, exposées ou non, qui font appel à function
     * (dans sa version inline)
     */
    void foo(){
        /*.... */
        function();
       /* ...*/
    }
    void void bar(){
        /*.... */
        function();
       /* ...*/
    }
    void doSomething(){
        /*.... */
        function();
       /* ...*/
    }
    Ca parait cool, hein D'autant plus que l'utilisateur de notre dll pourra créer son propre programme sous la forme de

    main.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(){
        /* ... */
        wrapper();
        /* ... */
        return 0;
    }
    Jusque là, tout est absolument génial! Mais, imaginons maintenant que nous voulions utiliser la version inline de la fonction dans une autre unité de compilation, par exemple dans le fichier

    other.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     
    void doSomethingElse(){
        /* comment avoir l'implémentation de fonction ici ????*/
    }
    Il y a plusieurs solutions, à vrai dire. La pire d'entre elle serait de copier l'implémentation de la fonction inline dans ce fichier, sous une forme qui deviendrait proche de
    other.cpp (V2)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    /* la fonction que l'on veut inliner */
    inliine function(){
        /* blabla */
    }
    void doSomethingElse(){
        /* et oui, ca marche!!! */
        function()
    }
    Pourquoi essentiellement parce que, si tu décide à un moment quelconque de modifier (par exemple, pour corriger un bug) le comportement de function, il y a toutes les chances pour que tu oublie de modifier ce comportement dans (au moins) un fichier d'implémentation. Tu n'auras pas respecté le DRY (Don't Repeat Yourself ou "ne vous répétez pas") et le résultat sera que "assez bizarement, parfois, la fonction marche très bien, et parfois, elle nous fait n'importe quoi"

    Une autre solution, moins mauvaise car elle respecte le DRY, consisterait à placer l'implémentation de la fonction inline dans un fichier séparé, sous une forme qui serait alors proche defunction.hpp (ou function.impl, par exemple)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #ifndef FUNCTION_HPP_INCLUDED
    #define FUNCTION_HPP_INCLUDED
    inline void function(){
       /* ...  bla, bla */
    }
    le fichier wrapper.hpp ne serait pas modifié, et les unités de compilations ressembleraient alors à quelque chose comme
    compile_unit.hpp
    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
    #include <wrapper.hpp>
    /* fournit tout à la fois la déclaration et l'implémentation de la fonction inline */
    #include <function.hpp>
    /* la fonction que l'on veut inliner */
    inliine function(){
        /* blabla */
    }
    /* la fonction wrapper */
    void wrapper(){
        function();
    }
     
    /* d'autres fonctions, exposées ou non, qui font appel à function
     * (dans sa version inline)
     */
    void foo(){
        /*.... */
        function();
       /* ...*/
    }
    void void bar(){
        /*.... */
        function();
       /* ...*/
    }
    void doSomething(){
        /*.... */
        function();
       /* ...*/
    }
    other.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    /* fournit tout à la fois la déclaration et l'implémentation de la fonction inline */
    #include <function.hpp>
    void doSomethingElse(){
        function()
    }
    DRY est respecté, et nous pourrions donc croire que "tout va pour le mieux dans le meilleur des mondes", non

    Hé bien, justement, non! Car la loi de Finagle nous dit que si tu laisses à "quelqu'un" (au développeur qui utilise ta bibliothèque, dans le cas présent) la possibilité de faire une connerie, ce n'est qu'une question de temps avant qu'il ne la fasse; et ce sera toujours au pire moment qui soit.

    En l'occurrence, si le développeur (ce sera peut-être toi-même!) qui utilise ta bibliothèque prend conscience d'une manière ou d'une autre de l'existence du fichier function.hpp, tu dois t'attendre à ce que ce ne soit qu'une question de temps avant qu'il ne décide d'utiliser function au lieu d'utiliser le wrapper.

    Cela ne devrait (théoriquement) pas trop porter à conséquence, mais un fait demeurera: ce n'est pas sous cette forme que tu avais prévu que ta bibliothèque serait utilisée.

    NOTA: il y aura forcément à un moment ou à un autre des situations dans lequelles tu n'auras pas d'autre choix que d'utiliser des fonctions inline (je pense, entre autres, au fonctions et aux classes template). Mais, tant que tu n'en as pas vraiment besoin, tu auras sans doute bien plus facile de ne pas t'en inquiéter; de faire "comme si cette possibilité n'existait pas"
    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

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

Discussions similaires

  1. [POO] Est-il possible de récupérer les arguments muets d'une fonction ?
    Par RomainVALERI dans le forum Général JavaScript
    Réponses: 24
    Dernier message: 16/11/2009, 13h51
  2. [Tkinter] Est-il possible de faire pivoter des PhotoImage ?
    Par sigmar_avenger dans le forum Tkinter
    Réponses: 9
    Dernier message: 06/01/2007, 15h18
  3. Est il possible de faire une fusion
    Par boy569 dans le forum Composants VCL
    Réponses: 3
    Dernier message: 07/02/2006, 13h58
  4. Est il possible de faire planter un système Unix
    Par Patrick PETIT dans le forum Administration système
    Réponses: 15
    Dernier message: 15/06/2004, 15h16
  5. est il possible de faire un trie sur un paramètre donné
    Par chtiboss dans le forum XSL/XSLT/XPATH
    Réponses: 8
    Dernier message: 17/03/2004, 11h51

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