Partage
  • Partager sur Facebook
  • Partager sur Twitter

Pointeur de fonction : maFonction(void) != maFonction() ?

Sujet résolu
    28 novembre 2011 à 20:12:54

    Bonsoir,

    je n'ai pas réellement de problème, mais plutôt une interrogation. Je l'ai bien soumise à Google mais je n'ai eu aucun résultat. Il faut dire aussi que je ne sais pas comment poser cette question à un algorithme. Cela ira peut-être mieux avec des humains.

    Soit un fichier de sources C, contenant :
    void maFonction(void (*f)(double)) { 
         ; 
    }
    
    void FUSR1() {
         ;
    }
    
    int main(void) {
         maFonction(FUSR1);
         return 0;
    }
    


    Ce code compile sans erreur ni avertissement avec GCC 4.6.2 (gcc -Wall) alors que je ne respecte pas le prototype de la fonction maFonction().


    Si maintenant on fait un changement (ajout de "void" en paramètre de FUSR1() ):
    void maFonction(void (*f)(double)) { 
         ; 
    }
    
    void FUSR1(void) {
         ;
    }
    
    int main(void) {
         maFonction(FUSR1);
         return 0;
    }
    


    GCC réagit avec un warning "incompatible pointer type", ce qui est le comportement attendu.


    Si on change à nouveau le code (suppression du paramètre de FUSR1 et ajout d'un deuxième paramètre dans la fonction attendue par maFonction) :
    void maFonction(void (*f)(double, float)) { 
         ; 
    }
    
    void FUSR1() {
         ;
    }
    
    int main(void) {
         maFonction(FUSR1);
         return 0;
    }
    


    Le compilateur réagit avec le même warning "incompatible pointer type" que précédemment.

    J'en déduis donc que FUSR1() != FUSR1(void) et je ne comprends pas la raison de ce comportement et je me dis qu'il doit y avoir une explication rationnelle. Une idée ?

    Merci d'avance.
    • Partager sur Facebook
    • Partager sur Twitter
      28 novembre 2011 à 20:52:47

      Salut,

      Il faut savoir que lorsque l'on ne spécifie pas le type et le nombres des arguments d'une fonction (comme c'est le cas pour la fonction FUSR1 dans ton premier et troisième exemple), cela ne signifie pas qu'elle n'attend aucun argument, mais cela veut dire que le type et le nombres de ses arguments est indéterminés. C'est la raison pour laquelle le compilateur n'émet aucun avertissement dans ton premier exemple: tu attends l'adresse d'une fonction ne retournant rien et prenant un double, le nombre et le type des arguments de FUSR1 étant inconnus, elle correspond bien à ce qui est demandé.

      Alors, je vois déjà venir la question qui suit:


      Oui mais, puisque le nombres d'arguments attendus par FUSR1 est indéterminé, pourquoi le troisième exemple ne compile-t-il pas sans avertissement?


      Parce qu'il y a une petite subtilité ^^
      Quand le compilateur dispose d'un prototype, c'est à dire que le type et le nombre des arguments sont connus, le compilateur converti les arguments dans le type des paramètres attendus par la fonction. Par contre, lorsque ces informations sont manquantes, le compilateur n'effectue pas de conversion et les arguments sont simplement promus. Concrètement, une expression de type entière et de rang inférieure ou égale à un int est promue en int (ou unsigned int suivant sa valeur) et une expression de type float est promue en double.

      Autrement dit, une fonction dont le nombre et le type de ses arguments n'est pas spécifié ne pourra jamais recevoir un paramètre de type float. Voilà pourquoi le compilateur te retourne un avertissement dans le troisième exemple. Remplace le type du deuxième paramètre par double et tu verras que cela compile sans avertissements ;)
      • Partager sur Facebook
      • Partager sur Twitter
        29 novembre 2011 à 1:22:11

        Merci pour ta réponse :D.

        Citation : Taurre

        Il faut savoir que lorsque l'on ne spécifie pas le type et le nombres des arguments d'une fonction (comme c'est le cas pour la fonction FUSR1 dans ton premier et troisième exemple), cela ne signifie pas qu'elle n'attend aucun argument, mais cela veut dire que le type et le nombres de ses arguments est indéterminés.


        C'est un peu "casse-gueule" ce comportement : j'attends des paramètres dont le nombre et le type sont inconnus ... du coup comment je fais pour les récupérer dans le code de la fonction ? Si, comme je le pense, on ne le peut pas, alors le fait que le nombre et le type soient indéterminés revient au même que de dire qu'il n'y a pas d'arguments. Si on peut récupérer des arguments indéterminés, alors ma question devient "un exemple d'utilisation d'une fonction ayant un nombre indéterminé d'arguments ?".


        Citation : Taurre

        C'est la raison pour laquelle le compilateur n'émet aucun avertissement dans ton premier exemple: tu attends l'adresse d'une fonction ne retournant rien et prenant un double, le nombre et le type des arguments de FUSR1 étant inconnus, elle correspond bien à ce qui est demandé.


        L'inconnu est donc promu double ou int en fonction, dans mon cas, du prototype de maFonction(). Pourquoi n'ont-ils pas considérés que l'inconnu = void, justement ?

        J'ai tenté de remplacer le deuxième argument du code 3 par un int et, en effet, cela fonctionne :).

        En tout cas, je déduis de cette expérience qu'il vaut mieux toujours préciser void lorsque l'on veut bien une fonction qui n'attend aucun argument.
        • Partager sur Facebook
        • Partager sur Twitter
          29 novembre 2011 à 5:31:47

          Bonjour

          Citation : guigui42


          C'est un peu "casse-gueule" ce comportement : j'attends des paramètres dont le nombre et le type sont inconnus ... du coup comment je fais pour les récupérer dans le code de la fonction ? Si, comme je le pense, on ne le peut pas, alors le fait que le nombre et le type soient indéterminés revient au même que de dire qu'il n'y a pas d'arguments. Si on peut récupérer des arguments indéterminés, alors ma question devient "un exemple d'utilisation d'une fonction ayant un nombre indéterminé d'arguments ?".



          Un exemple absurde
          void maFonction(void (*f)(double, int)) {
               ;
          }
          
          /* Déclaration */
          void FUSR1();
          
          int main(void) {
               maFonction(FUSR1);
               return 0;
          }
          
          
          /* Définition */
          void FUSR1(double a, double b, int c) {
             ;
          }
          


          Les seuls warnings sont du type

          warning: unused parameter ...
          • Partager sur Facebook
          • Partager sur Twitter
          Zeste de Savoir, le site qui en a dans le citron !
          Anonyme
            29 novembre 2011 à 11:53:19

            Mais c'est horrible ! :waw: Je suppose que pour faire propre il faut toujours mettre maFonction(void) dans son code, alors...
            • Partager sur Facebook
            • Partager sur Twitter
              29 novembre 2011 à 12:00:16

              Citation : GuiGui42


              C'est un peu "casse-gueule" ce comportement : j'attends des paramètres dont le nombre et le type sont inconnus ... du coup comment je fais pour les récupérer dans le code de la fonction ? Si, comme je le pense, on ne le peut pas, alors le fait que le nombre et le type soient indéterminés revient au même que de dire qu'il n'y a pas d'arguments. Si on peut récupérer des arguments indéterminés, alors ma question devient "un exemple d'utilisation d'une fonction ayant un nombre indéterminé d'arguments ?".



              Dans ton exemple, on ne peut en effet pas récupérer les arguments que tu enverras à ta fonction car sa définition ne précise aucun paramètre. Normalement, on utilise une déclaration et une définition séparée, comme dans le code que t'a donné GurneyH. Sinon, lorsque l'on souhaite un nombre d'arguments variable, on recourt à une ellipse et aux fonctions de l'en-tête stdarg.h (il y a un tutoriel à ce sujet sur ce site). Un exemple typique de fonction utilisant cette méthode est printf.

              Citation : GuiGui42


              En tout cas, je déduis de cette expérience qu'il vaut mieux toujours préciser void lorsque l'on veut bien une fonction qui n'attend aucun argument.



              C'est en effet la bonne habitude à suivre ;)
              • Partager sur Facebook
              • Partager sur Twitter
                29 novembre 2011 à 14:03:18

                @tous : Merci.

                J'avais pensé à une séparation déclaration/définition comme dans le code de GurneyH mais je ne voyais pas (et je ne vois toujours pas) l'intérêt de ne pas spécifier les paramètres dans la déclaration. Je me suis dis "ça peut servir dans un projet : tous les membres se mettent d'accord sur les prototypes des fonctions et ensuite chacun implémente de son côté une partie du projet" mais, en même temps, je me dis "puisqu'on définit les prototype en commun, autant le faire jusqu'au bout et donc de spécifier les paramètres attendus". Est-ce que j'ai raté un cas d'utilisation des fonctions déclarées sans paramètres ?
                • Partager sur Facebook
                • Partager sur Twitter
                  29 novembre 2011 à 16:14:29

                  Citation : GuiGui42


                  J'avais pensé à une séparation déclaration/définition comme dans le code de GurneyH mais je ne voyais pas (et je ne vois toujours pas) l'intérêt de ne pas spécifier les paramètres dans la déclaration. Je me suis dis "ça peut servir dans un projet : tous les membres se mettent d'accord sur les prototypes des fonctions et ensuite chacun implémente de son côté une partie du projet" mais, en même temps, je me dis "puisqu'on définit les prototype en commun, autant le faire jusqu'au bout et donc de spécifier les paramètres attendus". Est-ce que j'ai raté un cas d'utilisation des fonctions déclarées sans paramètres ?



                  Non non, il n'y a aujourd'hui plus d'intérêt à utiliser une déclaration au lieu d'un prototype. C'est simplement un héritage du C pré ANSI conservé pour des besoins de rétro-compatibilité ;)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    29 novembre 2011 à 22:28:38

                    Merci :D .

                    J'en ai fini donc je passe ce sujet en résolu (bon ok, j'ai mis du vert presque partout mais je pense sincèrement que ça aidera d'autres Zéros).
                    • Partager sur Facebook
                    • Partager sur Twitter

                    Pointeur de fonction : maFonction(void) != maFonction() ?

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown