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 :

Conversion de tableau vers va_list ?


Sujet :

C

  1. #1
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut Conversion de tableau vers va_list ?
    Bonjour à tous,
    Dans le cadre d'une campagne de portabilité visual studio / gcc je suis tombé sur une horreur dans notre codebase avec un cast d'un tableau vers un va_list.


    Tout d'abord voici le code qui nous est fourni sous forme de bibliothèque, c'est du code que je ne peux pas modifier. (Pour info c'est en fait à la base un code C++ avec des classes, d'ou l'écriture un peu bizarre mais le problème de fond est typique du C)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    struct String
    {
       char* m_chars;
    };
     
    struct StringArray
    {
        String* m_array;
    };
     
    formatV(const char* pszFormat, va_list args) { //...}
    char* getPattern() { //...}
    StringArray getParameters() {//...}
    Et voici la fonction qui pose problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void foo()
    {
       char* pattern = getPattern();
       StringArray parameters = getParameters();
       formatV(pattern, (va_list) parameters.m_array); // tada
    }
    J'ai encore du mal à y croire mais ça compile avec visual studio et donne le résultat attendu. L'astuce repose sur le fait la chaine pattern ressemble à qqchose du style "%s %s %s" et que StringArray contient un pointeur vers un tableau de char* contenant exactement le nombre de chaine attendu. Je suppose que par chance avec visual studio, va_list est effectivement un pointeur et qu'on émule donc ce qu'aurait fait un compilateur si foo avait était variadique et qu'il avait placé dans la pile les arguments de la fonction les un à la suite des autres.

    En passant sur GCC on se prend un erreur de compilation indiquant qu'il est impossible de convertir un pointeur de type String* en va_list (ce qui semble la moindre des choses) du coup j'aimerais en profiter pour corriger ce comportement indéterminé manifeste et le remplacer par du code légal.

    Le problème c'est que je n'ai en fait pas la moindre idée sur la bonne manière pour transformer mes paramètres qui sont empacketés dans un tableau dont le taille est connu au runtime vers une va_list. Des idées ?

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Il me semble qu'il n'y a pas de mécanisme standard (y compris dans C11) pour créer une va_list de toute pièces, hélas.
    GCC n'accepte pas va_start:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TestVaList.c|13|error: 'va_start' used in function with fixed args
    Et comme GCC utilise des built-in, tu ne peux même pas tricher en passant par une bibliothèque de Visual qui ferait juste la conversion!

    Par contre, il est peut-être possible de remplacer un hack par un autre pour appeler dynamiquement la fonction: Mon hack doit pouvoir être portable sous MinGW (mais pas sous *n*x, vu qu'il repose sur l'infrastructure COM).

    Sinon, quitte à passer par de l'assembleur, on peut faire un truc qui ne passe pas par COM, copie directement le tableau de paramètres sur la pile et appelle la fonction avec...
    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
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Merci pour la réponse.

    Pour l'absence de mécanisme standard c'est en effet bien ce qui semble émerger de ce que j'ai pu lire sur le sujet

    Je ne peux malheureusement pas utiliser la solution à base de COM car on passe en fait d'une solution wince 5.0 vers une plateforme linux ARM, dont je ne sais pas encore quel est le noyau ni quelle version de GCC est utilisée (je commence tout juste à travailler sur le sujet)

    Donc je pense que je vais essayer d'installer l’environnement linux puis essayer de trouver le même genre de hack que celui qu'on utilise avec VS (ou une va_list n'est qu'un typedef vers un char*) mais adapté à GCC.

    Sinon, quitte à passer par de l'assembleur, on peut faire un truc qui ne passe pas par COM, copie directement le tableau de paramètres sur la pile et appelle la fonction avec...
    Pfffiou mais faudrait d'abord que j’apprenne l'ARM, déjà que mes souvenirs de x86 sont loins
    Et en plus cette partie du code est compilé à la fois en ARM pour générer l'appli déployé sur cible mais aussi en x86 pour avoir une appli de simulation qui tourne sous windows.

  4. #4
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    - de memoire, il y a des ABI ou c'est difficile, voire impossible de batir un va_list sans faire d'appel. En particulier, va_start peut chercher des choses dans les registres.

    Sans hacks,

    - generalement on fonctionne dans l'autre sens, on batit un tableau a partir d'un va_list

    - il y a naturellement la methode

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    switch(sz) {
    case 1: f(sz, a[0]); break;
    case 2: f(sz, a[0], a[1]); break;
    case 3: f(sz, a[0], a[1], a[2]); break;
    ....
    }
    eventuellement autogenere.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Plutôt un switch(CountFormatSpecifiers(sz)), non?
    Avec, dans le cas de la famille printf(), un CountFormatSpecifiers() qui compterait le nombre de caractères '%' tout en ignorant les couples "%%".
    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.

  6. #6
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Plutôt un switch(CountFormatSpecifiers(sz)), non?
    Avec, dans le cas de la famille printf(), un CountFormatSpecifiers() qui compterait le nombre de caractères '%' tout en ignorant les couples "%%".
    J'ai, volontairement, pas indique comment trouver sz C'est un moyen. La taille du tableau en est un autre. Controler que c'est la meme est un bon exercice.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ah, tu utilisais sz comme abbréviation pour "taille"... Comme tu le passais en premier paramètre de la fonction, j'ai cru que c'était censé être le format (via abbréviation de "zero-terminated string"), qui ne pouvait pas servir d'entrée au switch()...
    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.

  8. #8
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    - il y a naturellement la methode

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    switch(sz) {
    case 1: f(sz, a[0]); break;
    case 2: f(sz, a[0], a[1]); break;
    case 3: f(sz, a[0], a[1], a[2]); break;
    ....
    }
    eventuellement autogenere.
    Très joli. Je dois bien avouer que cette solution ne m'avait même pas traversé l'esprit !
    Problème résolu donc, car on n'a jamais vraiment beaucoup de %s dans la chaine de format, donc un switch-case avec une bonne marge (disons jusqu'à 20) + un assert dans le default: et ça devrait largement suffire.

    Cerise sur le gâteau, c'est parfaitement portable ! Merci.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Tu peux aussi peut-être, si la chaîne est trop grande, la séparer en blocs de X, les formater séparément et concaténer les résultats...
    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.

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

Discussions similaires

  1. Conversion de tableau EXCEL vers table HTML en ligne
    Par superccman dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 10/01/2010, 10h55
  2. conversion type Image vers tableau
    Par elektronik-17 dans le forum Débuter
    Réponses: 6
    Dernier message: 22/08/2008, 00h47
  3. conversion tableau vers chaine de caractere
    Par sneb5757 dans le forum Réseau
    Réponses: 6
    Dernier message: 12/11/2006, 22h31
  4. [Think Pascal] Portage/conversion Think Pascal vers MAC/Windows/Linux
    Par Alain Vitry dans le forum Autres IDE
    Réponses: 1
    Dernier message: 19/03/2005, 11h24
  5. Conversion distance , angle vers coordonnées de points
    Par mat.M dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 26/03/2004, 22h55

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