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 :

Nombre variable de paramètres


Sujet :

C++

  1. #1
    Membre averti
    Avatar de rolkA
    Inscrit en
    Juillet 2003
    Messages
    324
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 324
    Points : 369
    Points
    369
    Par défaut Nombre variable de paramètres
    Bonjour. Ma question est toute simple. Je viens de m'apercevoir que ceci compile (que ce soit avec gcc, BCB, ou VisualC++, j'ai pu tout tester):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void func(...)
    {
    }
    Autrement dit, il n'est pas nécessaire que la fonction ait au moins un paramètre classique.
    Qu'en est-il exactement, que dit le standard à ce sujet ? Car dans tout ce que j'ai pu lire, il est indiqué que la fonction doit au moins avoir un paramètre classique, comme çà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void func(char* sz, ...)
    {
    }
    De plus, si on a pas moyen de savoir le nombre d'arguments effectivement passés, comment les récupérer ? Si ce n'est pas possible, quel est l'intérêt d'autoriser une telle syntaxe ?

    Merci d'avance.
    Un historique local pour Visual Studio 2005 et 2008 :
    http://www.codeplex.com/VLH2005

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    La norme dit :
    If the parameter-declaration-clause terminates with an ellipsis, the number of arguments shall be equal to or greater than the number of parameters specified. Where syntactically correct, “, ...” is synonymous with “...”.
    Rien n'interdit d'avoir un seul argument.

    Maintenant, comment y accèder ? Les macros va_arg va_end et va_start et le type va_list semblent là pour ça, mais comme la norme C++ ne les définit que par référence à la norme C que je n'ai pas, je ne peux pas en dire plus.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Membre averti
    Avatar de rolkA
    Inscrit en
    Juillet 2003
    Messages
    324
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 324
    Points : 369
    Points
    369
    Par défaut
    Citation Envoyé par JolyLoic
    Les macros va_arg va_end et va_start et le type va_list semblent là pour ça, mais comme la norme C++ ne les définit que par référence à la norme C que je n'ai pas, je ne peux pas en dire plus.
    Je sais çà, mais comment sais-tu où t'arréter dans la récupération des arguments si tu n'en a pas le nombre ?
    Exemple tiré du cours d'Emmanuel Delahaye:
    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
     
    #include <stdarg.h>
     
    /* Fonction effectuant la somme de "compte" paramètres : */
    double somme(int compte, ...)
    {
        double resultat=0;      /* Variable stockant la somme. */
        va_list varg;           /* Variable identifiant le prochain
                                   paramètre. */
        va_start(varg, compte); /* Initialisation de la liste. */
        while (compte!=0)       /* Parcours de la liste. */
        {
            resultat=resultat+va_arg(varg, double);
            compte=compte-1;
        }
        va_end(varg);           /* Terminaison. */
        return resultat;
    }
    Sans la variable compte, comment pourrait-on faire ?
    Un historique local pour Visual Studio 2005 et 2008 :
    http://www.codeplex.com/VLH2005

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Effectivement, en lisant la spec de ces macros (que comme j'ai dit, je ne connais pas, puisque je n'ai jamais eu besoin de les utiliser en C++, je trouve que le chaînage d'appel à la cout est supérieur aux varargs), j'ai l'impression que sans un argument classique, on a du mal à utiliser va_begin. Je ne comprend pas trop pourquoi.

    En effet, il me semble légitime dans ce contexte de vouloir créer une fonction concat qui concatène n char*, et qui s'appelle ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    char *JeanPoiret = concat("La ", "vache ", "à ", "mille ", "francs", NULL);
    Ma conclusion sur ce point est donc que l'on peut écrire une fonction int f(...), mais que dans ce cas, il n'est pas possible d'accèder aux arguments.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Membre averti
    Avatar de rolkA
    Inscrit en
    Juillet 2003
    Messages
    324
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 324
    Points : 369
    Points
    369
    Par défaut
    Citation Envoyé par JolyLoic
    En effet, il me semble légitime dans ce contexte de vouloir créer une fonction concat qui concatène n char*, et qui s'appelle ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    char *JeanPoiret = concat("La ", "vache ", "à ", "mille ", "francs", NULL);
    Oui et pourtant c'est impossible ! Mais comme tu dis, dans ce cas, une classe utilisant l'opérateur << résoud le problème.
    Un historique local pour Visual Studio 2005 et 2008 :
    http://www.codeplex.com/VLH2005

  6. #6
    Membre habitué Avatar de PINGOUIN_GEANT
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 149
    Points : 155
    Points
    155
    Par défaut
    Citation Envoyé par JolyLoic
    je trouve que le chaînage d'appel à la cout est supérieur aux varargs),
    si je comprends bien: cela remplace ce qu'on peut faire avec stdarg ?
    y'a-t-il des infos qq part car j'ai lu qu'il y avait une solution meilleure proposée plus tard (dans le cours Eckel) mais je n'ai jamais trouvé.
    Merci d'avance.
    " Tout homme est digne d'un parapluie." Stavroguine dans Les Démons de Dostoïevski.

  7. #7
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Le tout est d'avoir un moyen de stocker le nombre d'arguments. Après à l'exécution on n'aura pas vraiment de moyen de tester ce nombre ; il faut supposer que l'utilisateur ne se plante pas.

    Dans la famille C, les façons de stocker ce nombre :
    - si le premier truc reçu sera le nombre ou un format d'où il est extractible,
    - si on utilise un 0 terminal (là, problème aussi de format des choses reçues)
    - si le nombre est connu par ailleurs (genre tu peuples un vecteur qui est connu pour avoir 4 éléments)

    Dans les solutions C++, pour remplacer "...", on a :
    - les plages itérables (pour lesquelles on connait donc deux bornes) et autres vecteurs ; que cela soit pour des données homogènes, ou même hétérogènes si on utilise des paramètres variants.
    - l'opérateur d'injection ou toute autre fonction utilisée pour injecter.
    - et aussi variante (je l'aime bien celle là) utiliser une classe (éventuellement proxy) qui se définit l'opérateur () (qui renvoit le proxy d'abord, puis *this), ce qui permet d'écrire des choses comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Toto toto(p1, p2, p3)
         ("toto") (42) (M_PI) (titi)
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  8. #8
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par JolyLoic
    Effectivement, en lisant la spec de ces macros (que comme j'ai dit, je ne connais pas, puisque je n'ai jamais eu besoin de les utiliser en C++, je trouve que le chaînage d'appel à la cout est supérieur aux varargs), j'ai l'impression que sans un argument classique, on a du mal à utiliser va_begin. Je ne comprend pas trop pourquoi.

    En effet, il me semble légitime dans ce contexte de vouloir créer une fonction concat qui concatène n char*, et qui s'appelle ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    char *JeanPoiret = concat("La ", "vache ", "à ", "mille ", "francs", NULL);
    Ma conclusion sur ce point est donc que l'on peut écrire une fonction int f(...), mais que dans ce cas, il n'est pas possible d'accèder aux arguments.
    Il faut un premier argument avant ... qui permet d'identifier le type et le nombre de valeurs qui lui sont passées. Que se passerait-il si on passait ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    concat("La ", "vache ", "à ", 1000, " francs", NULL);
    Sinon on avait déjà parlé de ça ici :
    http://www.developpez.net/forums/viewtopic.php?t=248470

    Luc> c'est quoi l'opérateur d'injection ?
    Et sinon on ne peut pas arriver à quelque chose en surchargeant l'opérateur virgule ?

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    En fait, je pense que le premier argument sert surtout à récupérer l'adresse du premier argument optionnel sur la pile (celui juste après donc), ce que fait la macro va_begin. Sans cet argument, comment récupérer l'adresse des arguments variables ?
    Si on se sert d'une variable terminale (NULL) plutot que d'une chaîne decrivant le format il faut faire confiance à l'utilisateur, en l'occurence il ne devra pas donner autre chose que du char* à concat(), mais à part cette restriction c'est tout à fait possible. Apres tout, même avec une chaine decrivant le format, rien ne nous empeche de nous gourrer (ce qui m'arrive d'ailleurs souvent lorsque j'utilise scanf & compagnie ).

    L'opérateur d'injection c'est <<, >> est l'opérateur d'extraction (enfin c'est toujours de cette manière qu'on en parle, en tout cas).

    Pour l'opérateur virgule, on peut faire des trucs amusants ; j'avais codé un bidule qui permettait d'écrire quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int> v = 1, 2, 3, 5, 6, 7;
    Mais à part pour s'amuser, je n'ai jamais vu de surcharge de cet opérateur, je ne sais pas si c'est une si bonne solution. Autant surcharger l'opérateur <<, ça revient plus ou moins au même je pense.

  10. #10
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Disons que l'opérateur virgule, ça va bien mais pas pour n'importe quoi.
    Je n'ose même pas imaginer les effets de bords avec l'écriture présente où il n'y a que des entiers : à droite comme à gauche.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  11. #11
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Aurelien.Regat-Barrel
    Que se passerait-il si on passait ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    concat("La ", "vache ", "à ", 1000, " francs", NULL);
    La même chose que si on passe un mauvais argument à un printf : Boom ! De préférence plus loin dans le code, à un endroit sans rapport. C'est après avoir passé plus d'une journée à temps plein à débugger une telle horeur (et on ajoute des printf de debug, et l'erreur change d'endroit...) que j'ai achevé de bannir printf et les varargs de mon vocabulaire.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  12. #12
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Luc Hermitte
    Disons que l'opérateur virgule, ça va bien mais pas pour n'importe quoi.
    Je n'ose même pas imaginer les effets de bords avec l'écriture présente où il n'y a que des entiers : à droite comme à gauche.
    Ca marche bien, parce que l'opérateur = est prioritaire par rapport à l'opérateur ,

    De mémoir, les gens de blitz ou d'autre bibliothèques de ce genre utilisent cette syntaxe pour initialiser les tableaux.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  13. #13
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Je n'avais pas percuté ce détail dans les priorités.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

Discussions similaires

  1. procedure acceptant un nombre variable de paramètres
    Par pifou25 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 30/03/2007, 11h08
  2. Nombre variable de paramètres
    Par Invité(e) dans le forum Langage
    Réponses: 6
    Dernier message: 20/02/2007, 14h58
  3. [T-SQL] Procédure à nombre variable de paramètres ?
    Par NeoMan dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 28/12/2005, 15h07
  4. Réponses: 9
    Dernier message: 24/05/2005, 16h34

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