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 :

création d'une va_list


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 33
    Par défaut création d'une va_list
    Salut,

    Voilà le tit problème :
    Le système, développé en C, sur lequel je bosse s'interface avec un système SAP. Je récupère de celui-ci des chaines références (éléments standardisés) et un format à la mode sprintf.
    Le nombre de chaines transmises est variables et non contrôlé. Pour cela, je devrais recevoir un char ** qui contient mes références.
    Exemple :
    mon char ** contient 3 chaines : chaine1/chaine2/chaine3
    mon format est le suivant :
    "L'objet de reference %s ne peut être associé à l'objet de reference %s sur le plan %s".
    De mon côté je dois associer le format et les chaines afin d'afficher un message à l'utilisateur du style :
    L'objet de reference "chaine1" ne peut être associé à l'objet de reference "chaine2" sur le plan "chaine3".
    Comme ça rien de compliqué mais le message à afficher pouvant être variable et le nombre de références aussi, il a été décidé de réaliser une interface portable. Vous me direz "s'il passent à la fois le format et les chaines à y intégrer pourquoi se tracasser et ne pas passer directement la chaine déjà construite"?
    En fait, de notre côté les références passées par SAP, qui ont une signification pour le système, doivent d'abord passer par une moulinette assez complexe pour être traduites et avoir une signification pour l'utilisateur. On se trouve donc plutôt avec un système comme suit :

    mon char ** contient 3 chaines : chaine1/chaine2/chaine3
    mon format :
    "L'objet de reference %s ne peut être associé à l'objet de reference %s sur le plan %s".
    ma moulinette :
    moulinette(&chaine1) => chaine1bis
    moulinette(&chaine2) => chaine2bis
    moulinette(&chaine3) => chaine3bis

    L'objet de reference "chaine1bis" ne peut être associé à l'objet de reference "chaine2bis" sur le plan "chaine3bis".


    Voilà pour que vous connaissiez le contexte de mon problème, maintenant la question :
    Le problème peut se traiter par travail sur la chaine directement, je sais faire mais j'aime pas trop.
    J'ai vu qu'il était possible de faire un truc de ce style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdarg.h>
     
    void traiteArgs(char *format, ...)
    {
    	char s[500];
    	va_list argptr;
    	int cnt;
     
    	va_start(argptr, format);
    	cnt = vsprintf(s, format, argptr);
    	va_end(argptr);
     
    	printf(s);
    }
    Avec ça je pourrait traiter de façon sympa ma liste variable d'arguments.
    Mais va_list est un objet créé par le compilateur C que je ne maîtrise pas.
    Moi, ce que je reçois est une série de chaines et un format, je voudrais pouvoir créer le va_list avec ces chaines. Est-ce possible ? Merci de vous pencher sur le problème...

    NB : en fait le problème vient du fait qu'en C on ne puisse pas (à ma connaissance) construire une chaine avec une fonction et ses arguments puis la faire évaluer... pour exécuter la fonction appelée dans la chaine... si vous avez une ouverture là dessus je suis preneur.

  2. #2
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    Tu peux résoudre ce problème avec une fonction à trois arguments
    arg1 le nombre d'arguments effectifs de la fonction
    arg2 un tableau décrivant le type des arguments effectifs
    arg3 : un tableau de void * contenant les arguments

    exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int myfonc(int arg1, type_t tabType[], void *tabArg[]);
    avec
    arg3 = 3
    tabType[0] = 0; <== représente un entier
    tabType[1] = 1; <== représente une chaîne
    tabType[2] = 2; <== représente un float
     
    tabArg[0] = (void *) 15; <== arg1 est un entier
    tabArg[1] = (void *) "Hello World"; <== arg2 est une chaîne
    tabArg[2] = (void *) 15.0; <== arg3 est un float (à vérifier tout de même car je ne suit pas sur que ça fonctionne, peut être dans ce cas considérer l'adresse d'une variable contenant un float)
    Mais j'espère que tu as compris le principe.
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 33
    Par défaut
    Excuse-moi mais je n'ai pas compris comment exploiter dans un printf (avec un format) les arguments ainsi découpés? Parce que c'est à peu près ce que je reçois... Je peux construire un va_list avec ça?
    Merci quand même de ta réponse.

  4. #4
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    Ça m'apprendra à ne pas lire le post en entier
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  5. #5
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    Si j'ai bien compris ton problème (maintenant que j'ai lu la question), tu as une chaîne format strformat avec un certain nombre de %s à remplacer par des arguments fourni par un char **tab qui doivent d'abord être traités avant de les afficher.
    Moi, je ferais comme celà :
    je recopierai la chaine strformat caractère par caractère dans la chaîne cible, et à chaque fois que je rencontre la chaîne %s je vais chercher l'argument à écrire dans le tableau des char **.
    Je simule un peu le va_arg.
    C'est moins sexy que le va-arg mais au moins je "contrôle" tout (mais j'ai comme l'impression que c'est ce que tu ne voulais pas faire !).
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  6. #6
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Pourquoi eviter va_arg, elle convient parfaitement dans cette situation.
    Une premiere fonction variadic cree la va_list avec va_start, et la passe a une fonction qui prend cette va_list en argument, enfin on termine la va_list par va_end. On connait le nombre d'arguments par l'analyse de la chaine de caractere passee en premier parametre.
    La fonction qui utilise la va_list accede aux arguments en appelant va_arg autant de fois que necessaire.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 33
    Par défaut
    Bien sûr que l’utilisation d’une va_list convient. La fonction traiteArgs telle qu’elle est présentée dans mon pemier post a été testée et fonctionne. Le problème se situe à l’appel de cette fonction :
    A la base, j’ai un nombre d’arguments, un char** contenant ces arguments et ma fonction traiteArgs.

    J’ai une solution vers laquelle à priori je vais me diriger, c’est celle prônée par Trap D, que je remercie au passage :
    Traiter la chaine format et insérer les chaines au fur et à mesure que je trouve un %s.
    Mais au départ elle ne me plaisait pas trop et c’est pourquoi j’en ai cherché d’autres, et j’ai notamment expérimenté traiteArgs. Cette solution me plait mais son appel est complexe dans mon cas


    J’ai une solution dégueulasse pour utiliser traiteArgs(): soit Arg le char** qui contient mes arguments.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if (nbArguments == 1)
    traiteArgs(format, Arg[1])
    else if (nbArguments == 2)
    traiteArgs(format, Arg[1], Argv[2])
    else if (nbArguments == 3)
    traiteArgs(format, Arg[1], Argv[2], Argv[3])
    etc…
    jusqu’à 100?
    Beurk j’aime pas!


    J’ai deux solutions propres « virtuelles » (parce que je ne sais pas les mettre en œuvre) pour utiliser traiteArgs() :
    Solution 1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Char * commande = NULL;
     
    (je vous passe les allocs mémoire…)
    Strcpy(commande, «traiteArgs(format ») ;
    For (int i=0 ; i<nbArguments ; i++)
    {
    Strcat (commande, “,”);
    Strcat (commande, Arg[i]); 
    }
    Strcat (commande, “));
    Et ce qui me manque : “eval (commande);” qui exécuterait la fonction continue dans la chaîne. Je crois pas que ça existe en C (system c'est bon pour les binaires ou les commandes shell).

    Solution 2 :

    Je fais un appel comme ça : traiteArgs(format, Arg) où Arg est mon char**
    Et à l’intérieur de traiteArgs je transforme mes chaines en va_list pour pouvoir les exploiter mais ça… je ne sais pas si c’est possible.

    Quoiqu’il en soit merci pour tout… j’espère avoir une lueur d’espoir.

  8. #8
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Et à l’intérieur de traiteArgs je transforme mes chaines en va_list pour pouvoir les exploiter mais ça… je ne sais pas si c’est possible
    Mais va_list est juste un pointeur qui est initialisé par la macro va_start à l'adresse de la variable locale spécifiée + sa taille. Ce n'est rien de plus.

    Si je comprends: Tu as un tableau de chaines et tu ne connais pas directement le nombre de chaines qui est spécifié dans le format. Tu dois modifier ces chaînes avant de les sortir en utilisant le format spécifié.
    Si on obtient un tableau de chaînes modifiées, l'application du format est simple : Par exemple :
    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
    void traiteArgs(char *fmt, char** tab)
    {
       char buffer[80];
       vsprintf(buffer, fmt, tab);
       printf("%s\n", buffer);
    }
    int main(void)
    {
       char string1[] = "abc";
       char string2[] = "def";
       char string3[] = "hij";
       char* tab[3];
       tab[0] = string1;
       tab[1] = string2;
       tab[2] = string3;
       traiteArgs("premier %s deuxième %s dernier %s ", tab);
       return 0;
    }
    La forme en tableau des chaînes initiales se prètent bien à leur modification individuelle, le problème est qu'on ne connait pas leur nombre à priori. La solution la plus simple n'est-elle pas alors de compter les %s du format? Ce nombre connu, on connaît la taille du tableau des chaînes d'origine et on peut créer un tableau de nouvelles chaîne.
    Je ne voie pas pourquoi on a besoin de va_list et compagnie, mais je n'ai peut-être pas compris le problème

  9. #9
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Citation Envoyé par diogene
    Je ne voie pas pourquoi on a besoin de va_list et compagnie, mais je n'ai peut-être pas compris le problème
    Le probleme, c'est que l'utilisation de vsprintf dans ton exemple est un peu acrobatique:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    toto4.c: In function `traiteArgs':
    toto4.c:8: warning: passing arg 3 of `vsprintf' from incompatible pointer type
    Il va bien falloir utiliser une va_list, si on veut faire les choses proprement.

  10. #10
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Citation Envoyé par diogene
    La solution la plus simple n'est-elle pas alors de compter les %s du format? Ce nombre connu, on connaît la taille du tableau des chaînes d'origine et on peut créer un tableau de nouvelles chaîne.
    Oui, c'est exactement comme cela que procedent printf, fprintf, sprintf pour connaitre le nombre d'arguments qu'elles doivent attendre.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 33
    Par défaut
    Merci à tous, je vais compter les %... j'ai déjà écrit la fonction... je trouvais ça moins séduisant , mais à défaut.

    A bientôt .

  12. #12
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    toto4.c:8: warning: passing arg 3 of `vsprintf' from incompatible pointer type
    Mon compilateur (Borland cbuider6) ne râle pas. La définition de va_list est ici void *, mais ce n'est peut être pas pareil partout. Peut être avec un transtypage de l'argument.

  13. #13
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Citation Envoyé par diogene
    La définition de va_list est ici void *, mais ce n'est peut être pas pareil partout.
    J'aimerais bien te dire quelle est la definition de va_list chez moi, mais trouver un typedef dans les header GNU, ce n'est pas facile...

  14. #14
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par DaZumba
    Citation Envoyé par diogene
    La définition de va_list est ici void *, mais ce n'est peut être pas pareil partout.
    J'aimerais bien te dire quelle est la definition de va_list chez moi, mais trouver un typedef dans les header GNU, ce n'est pas facile...
    De toutes façons, ça n'a aucune importance. C'est un type 'opaque' dont le codeur n'a pas se soucier des détails.

  15. #15
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    De toutes façons, ça n'a aucune importance. C'esty un type 'opaque' dont le codeur n'a pas se soucier des détails.
    C'est vrai, mais j'étais curieux de savoir ce qui se cachait derriere le système va_list et consort.

  16. #16
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par diogene
    <...>j'étais curieux de savoir ce qui se cachait derriere le système va_list et consort.
    Ca dépend de l'implémentation

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

Discussions similaires

  1. Réponses: 14
    Dernier message: 09/04/2004, 13h44
  2. [amc designer] création d'une base postgresql
    Par david42 dans le forum PostgreSQL
    Réponses: 9
    Dernier message: 12/03/2004, 11h08
  3. Création d'une base avec IbConsole
    Par Lucien dans le forum Outils
    Réponses: 3
    Dernier message: 02/03/2004, 18h34
  4. création d'une batabse .gdb
    Par jejestyle dans le forum Bases de données
    Réponses: 3
    Dernier message: 23/02/2004, 00h29
  5. [BES] Création d'une variable d'environnement
    Par NGI80 dans le forum Autres
    Réponses: 2
    Dernier message: 17/10/2002, 07h31

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