Forum Programmation.c fonction à nombre variable de paramètre

Posté par  .
Étiquettes : aucune
0
22
déc.
2005
Bon j'ai commencé à m'attaquer au fonctions à nbr variables de paramètre, j'utilise pour cela la lib <stdarg.h>
ça marche bien. Mais je cherche à faire un peu plus compliqué...
j'ai une première fonction:
int somme(int nbr, ...)
{
int i,s=0;
va_list(pt);
va_start(pt,nbr);
for(i=0 ; i < nbr ; i++) /* "<" = infèrieur, mais je n'arrive pas à le faire passer*/
s=s+va_arg(pt,int);
va_end(pt);
return s;
}

et je voudrai l'utiliser dans une fonction moyenne par exemple, mais je ne sais pas si on peu passer les arguments "..." à une autre fonction, par exemple pour faire un truc du style:
float moyenne(int nbr, ...)
{
return (somme(nbr,...)/nbr);
}

ou bien si il faut que je stocke les argument de moyenne dans un tableau et les restitus à la fonction somme?
je sais pas si je me suis fait comprendre, j'espère que oui :-)
merci d'avance.
  • # HUm

    Posté par  (site web personnel) . Évalué à 1.

    A ma connaissance, non ce n'est pas possible.

    Tu devrais effectivement stocker tous les 1ers paramètres recus dans un tableau, et faire suivre ce dernier à somme.
    • [^] # Re: HUm

      Posté par  . Évalué à 0.

      Ok je ferai avec le tableau! jusqu'au momen où on m'indiquera que c'est possible ;-)
      merci pour la réponse....
      et pendant que j'y suis sur ces fonctions, première chose, le nombre de paramètre est-il infini (ou quasi, la limite étant la mémoire de l'ordi)
      ou y a-t-il une limite plus petite?
      et ensuite, ya t'il un moyen pour "revenir d'un cran" sur la variable précédente ou va_args efface t'il les variables après les avoir récupérée ?
      • [^] # Re: HUm

        Posté par  . Évalué à 2.

        "et ensuite, ya t'il un moyen pour "revenir d'un cran" sur la variable précédente ou va_args efface t'il les variables après les avoir récupérée ?"

        bon, ça c'est deux questions en fait.

        Y'a-t-il un moyen de revenir d'un cran ?
        La réponse est non. Sur une va_list, tu ne peux appeler que va_start, va_arg et va_end.
        L'effet de toute autre utilisation d'une va_list est indéfini.

        va_args efface-t'il les variables après les avoir récupérées ?
        On va dire que je suis négatif, mais encore une fois, la réponse une non.
        Tu as tout à fait le droit d'appeler plusieur fois va_start. Ca te repositionner à chaque fois sur le début de la liste. Par contre, je ne sais pas si tu peux imbriqué les appels (genre refaire un va_start entre un va_start et un va_end). Dans le doute, je ne m'y risquerais pas.

        Tu peux aussi jeter un oeil à va_copy
    • [^] # Re: HUm

      Posté par  . Évalué à 2.

      ouaip. J'avais aussi envie de faire des trucs comme ça y a pas longtemps, mais en C, il n'y a pas de façon portable de construire dynamiquement une va_list.

      dans la FAQ cd comp.lang.c :
      http://www.eskimo.com/~scs/C-faq/q15.12.html
    • [^] # Re: HUm

      Posté par  (site web personnel) . Évalué à 2.

      finallement, une va_list n'est qu'une liste de pointeurs en choppant l'adresse du premier élément de la va_list, on connait l'adresse du suivant tel que adress_va2 = (adresse_va1 + sizeof(void*)) ...

      bref, on placant l'adresse du premier parametre de la va_list en parametre de la fonction somme, il n'est pas impossible que cela fonctionne!

      A+
      Mathieu
      • [^] # Re: HUm

        Posté par  . Évalué à 2.

        Je m'y risquerais pas, la définition de va_list dépend énormément de la plateforme sur laquelle tu te trouves (par plateforme, je pense à processeur là, ça dépend peut être aussi de l'OS). Ie, ton truc fonctionne peut être sur x86, mais sur ppc je demande à voir (ça marche peut être, mais sans tester je me risquerais pas à supposer que tout marchera bien).
  • # macro à nombre variable d'arguments

    Posté par  . Évalué à 1.

    Tu peux éventuellement utiliser une macro à nombre variable d'arguments :

    #define MOYENNE(nbr, args...) (somme((nbr), args) / (nbr))


    utilisation :
    float f = MOYENNE(3, 1, 2, 3);

    Après, faut aimer les macros :)
    • [^] # Re: macro à nombre variable d'arguments

      Posté par  . Évalué à 0.

      Je ne comprend pas trop la définition de la macro:
      #define MOYENNE(nbr, args...) (somme((nbr), args) / (nbr))

      à quoi correspond la variable "args..."?
      En gros on transmet les "..." à la fonction somme?
      • [^] # Re: macro à nombre variable d'arguments

        Posté par  . Évalué à 1.

        tu fais un copier/coller de ce que j'ai écrit, c'est la syntaxe à utiliser pour définir et utiliser la liste de paramètres variable d'une macro.

        En fait, teste, et tu veras ! ;)
        • [^] # Re: macro à nombre variable d'arguments

          Posté par  . Évalué à -1.

          Les copiers/coller c'est gentil mais c'est pas trop ce que je recherche, je cherche plutôt à comprendre, car il est bien évident que je ne cherche pas simplement à faire une fonction moyenne réutilisant une fonction somme.
          Je veu pouvoir réapliquer ce que j'ai appris dans d'autres exemples....
          mais c'est gentil quand-même!
          • [^] # Re: macro à nombre variable d'arguments

            Posté par  . Évalué à 2.

            ok, je développe :

            tu copies la ligne dans ton fichier, exemple :

            macrotest.c :

            #define MOYENNE(nbr, args...) (somme((nbr), args) / (nbr))
             
            int
            main(int argc, char *argv[])
            {
              float f = MOYENNE(3, 1, 2, 3);
            }



            Pour voir ce que ça fait : gcc -E macrotest.c (tu fais passer le préprocesseur pour étendre la macro), ce qui donne :

            int
            main(int argc, char *argv[])
            {
              float f = (somme((3), 1, 2, 3) / (3));
            }


            Change les paramètres de MOYENNE dans le main, recommence la procédure ci dessus, et vois ce que ça donne.

            Finalement, après quelques tests, tu te rends compte que la liste de paramètres variables se note nom... dans le prototype de la macro, et qu'on l'appelle par nom dans le corps de la macro.


            Si tu as toujours des doutes, le texte "macro à nombre variable d'arguments" envoyé à google ( http://www.google.fr/search?hl=fr&q=macro+%C3%A0+nombre+(...)
            ) te renvoie entre autres la page : http://fr.wikibooks.org/wiki/Programmation_C_Pr%C3%A9process(...)
            et libre à toi d'en trouver d'autres si tu veux te documenter sur le sujet.

            Tout ça pour dire : vouloir savoir, c'est bien, attendre que ça tombe tout cuit, ça l'est moins. Quand tu as quelques pistes, si tu ne fais pas l'effort de fouiller par toi même, tu ne vas pas aller bien loin :-<

            bon courage quand même.
            • [^] # Re: macro à nombre variable d'arguments

              Posté par  . Évalué à 0.

              merci pour la réponse et dsl pour ma question préalable...
              mais c'est juste que lorsque je regarde sur la page http://fr.wikibooks.org/wiki/Programmation_C_Pr%C3%A9process(...) , et bien il y a une macros comme:

              #define debug(message, ...) fprintf( stderr, __FILE__ ":%d:" message "\n", __LINE__, __VA_ARGS__ ),

              et içi il n'ya pas de 'nom...' comme tu le dis, c'est pour ça que je ne comprend pas trop comment ça marche, comprend que se soit un peu déroutant....
              encore dsl
  • # il suffit de faire une fonction qui accepte une va_list

    Posté par  . Évalué à 1.

    en fait, il suffit de passer le va_list en argument.
    c'est utilise tres frequement, notamment pour appeller vfprintf.

    si je veux faire une fonction qui log au moyen d'une structure log je peux par exemple ecrire

    struct loginfo {
    const char *channel;
    FILE *fd;
    };

    void
    log_log(struct loginfo *li, const char *fmt, ...)
    {
    va_list ap;

    fprintf(li->fd, "%s: ", channel);
    va_start(ap, fmt);
    vfprintf(li->fd, fmt, ap);
    va_end(ap);
    fprintf(li->fd, "\n");
    }

    int
    main(int ac, char **av)
    {
    struct loginfo li;

    memset(&li, 0, sizeof (struct loginfo));
    li.fd = stdout;
    li.channel = 'monprog';
    log_log(&li, "ca marche tout comme printf, %s", "c'est vraiment trop bien");
    return 0;
    }

    en resume y aura pas trop de soucis pour transposer de ton cote:

    int
    moyenne(int nbr, ...)
    {
    int sum;
    va_list ap;

    va_start(ap,nbr);
    sum = somme(nbr, ap);
    va_end(ap);
    return sum / nbr;
    }

    int
    somme(int nbr, va_list args)
    {
    int sum;

    for (sum = 0; nbr--;)
    sum += va_arg(args, int);
    return sum;
    }

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.