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 :

Enregistrer des paramètres pour l'appel d'une autre fonction


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut Enregistrer des paramètres pour l'appel d'une autre fonction
    Bonjour,

    Je recherche à faire des sortes de lambda en 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
    15
    16
    17
    18
    struct {
         void *slot;
         Arguments argument;
    } Lambda;
     
    void foo(int);
    void foo2(char, bool);
    void foo2toi(bool);
     
    Lambda x[3] = { makeLambda(foo, 45),
                            makeLambda(foo2, 'e', true),
                            makeLambda(foo2toi, false) };
     
    // ailleurs dans le code
     
    executer(x[0]); //appelle foo(45);
    executer(x[1]); //appelle foo2('e', true);
    executer(x[2]); //appelle foo2toi(false);
    Est-ce que vous auriez une idée de comment je pourrais faire et comment sauvegarder les arguments ?

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Pourquoi codes-tu en C ? Entre ça et ta précédente discussion (du neuf d'ailleurs ?), tu donnes de plus en plus l'impression que le C n'est pas le langage que tu souhaites utiliser

    Ce que tu fais me fais penser à ce qui est dit là : http://msmvps.com/blogs/jon_skeet/ar...-language.aspx
    J'ai le bouquin dont il parle et c'est comme ça que j'ai trouvé ce lien. C'est bien de ne pas se limiter à ce que propose le langage mais il faut aussi être capable de ne pas aller trop loin. C'est l'objet de la première partie dans le lien.

    Pour revenir à ton problème, je pense que tu auras le même genre de problème qu'avec la discussion précédente : la généricité. Si toutes tes fonctions avaient le même prototype, il me semble voir un embryon d'idée. Mais avec des prototypes différents, je sèche un peu… Peut-être en rajoutant un paramètre "type" pour indiquer le prototype souhaité et faire un switch / case dans makeLambda(). Il y a par contre le risque d'avoir des warnings de type insolubles, sauf à caster implicitement mais il n'y a plus alors de vérification de types par le compilateur.

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Pourquoi codes-tu en C ?
    Je code en C++ en fait mais j'ai besoin d'avoir une API C

    J'ai trouvé une méthode légèrement plus simple et j'ai alors utilisé un define un peu verbeux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SIGNAL( signal, (bool a, int b), (a,b) )
    Plus tard, je pourrais ajouter un mot clé que je remplacerait par ma macro.

    Pour revenir à ton problème, je pense que tu auras le même genre de problème qu'avec la discussion précédente : la généricité. Si toutes tes fonctions avaient le même prototype, il me semble voir un embryon d'idée. Mais avec des prototypes différents, je sèche un peu… Peut-être en rajoutant un paramètre "type" pour indiquer le prototype souhaité et faire un switch / case dans makeLambda(). Il y a par contre le risque d'avoir des warnings de type insolubles, sauf à caster implicitement mais il n'y a plus alors de vérification de types par le compilateur.
    J'ai trouvé un début de réponse.
    Déjà, si les arguments ont la même taille, le type importe peu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void foo(char a);
     
    void (*ptrFoo)(uint8_t a) = (void (*) (uint8_t) )foo;
     
    ptrFoo( 'a' ); // marche
    Donc il faut stocker la taille de chaque argument mais pas leurs type.

    Après, le seul problème c'est qu'il faut stocker les arguments.
    A l'aide d'une fonction de serialisation, c'est tout à fait possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char * serialise(size_t * taille_des_arguments, ...);
    Le seul problème, c'est pour deserialiser les arguments et les passer à la fonction.
    Il me faut une fonction de deserialisation par "paramètres possibles" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    deserialise_8_32_64(args, slot); // appelle slot avec les arguments qui ont 8bits, 32 bits et 64 bits.
    deserialise_16_8_128(args, slot2); // appelle slot2 avec les arguments qui ont 16 bits, 8 bits et 128 bits.
    Je vais donc devoir rajouter à ma macro SIGNAL quelques paramètres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SIGNAL( signal, (bool a, int b), (a,b), deserialise_8_32, {sizeof(bool), sizeof(int) } )
    J'aimerais bien virer le 4 ème argument et trouver la bonne fonction en fonction du 5ème argument...
    Peut-être qu'en remplaçant toutes les fonctions deserialise par une unique fonction... mais il faudrait que je regarde comment je pourrais faire

    Après, je ferais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    signal signal(bool, int);
    Et quand j'exécuterais un petit programme de ma composition, il m'écrira :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SIGNAL(signal, (bool a, int b), (a,b), ????, {sizeof(bool), sizeof(int})
    Donc j'ai presque fini \o/

    EDIT : Le préprocesseur C est tout de même plus que décevant, on a même pas un équivalant à sizeof() pour le préprocesseur
    Peut-être que je vais donner quelques limitations du style : 4 arguments max et 4 tailles possibles

  4. #4
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Je suis en train de penser...

    Pour un prototype donné, et quelque soit le compilateur/OS/options du compilateur, les arguments seront toujours mis aux "mêmes endroits", sinon va_list ne pourra pas fonctionner non-plus. Il est donc théoriquement possible de copier la liste des paramètres de façon générique puis plus tard les remettre en mémoire avant d'appeler la fonction en assembleur avec call.

    Ainsi je n'aurais même pas à m'enquiquiner.
    Faut que je regarde de plus près comment va_list trouve ses arguments.

  5. #5
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Bonjour,

    J'arrive à copier la pile assez simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    char * faa(int a, ..., int b)
    {
            static char buffer[4096];
            int taille = sizeof(a) + ((char *)&a - (char *)&b);
            printf("%d\n", taille);
            memcpy(buffer, (void*)&b, taille);
            return &buffer;
    }
    Par contre, pour l'appel j'ai essayé de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Type t = faa(1, ..., 2);
    ((char *)(*)(Type)faa)(t);
    Et ça marche presque.
    Le seul problème, c'est quand certaines variables sont passées dans des registres

    Il faudrait que j'en sache plus sur l'ABI C pour savoir dans quels cas les registres sont utilisés.
    Sinon, je suis obligé de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Type t = faa(1, ..., 2);
    // on extrait les valeurs à partir de t
    ((char *)(*)(int, ..., int)faa)(a, ..., b);
    Ce qui demanderai d'avoir grosso modo une fonction par suite de taille d'argument possibles.

    Personne ne sait ce que dit le standard C au niveau de l'ABI des appels de fonctions ?

  6. #6
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 150
    Billets dans le blog
    150
    Par défaut
    Bonjour,

    Dans le style violent que vous faisiez avant, pourquoi ne pas sauvegarder les va_list ? et faire une fonction replay() qui prend une va_list directement.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  7. #7
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    char * faa(int a, ..., int b)
    {
            static char buffer[4096];
            int taille = sizeof(a) + ((char *)&a - (char *)&b);
            printf("%d\n", taille);
            memcpy(buffer, (void*)&b, taille);
            return &buffer;
    }
    Le comportement est indefini ici. Tu retournes l'addresse d'un buffer qui est dans une frame de la stack qui a ete depilee par ret. Tu ne peux que retourner buffer par copie, car le compilateur est assez malin pour copier le buffer d'une frame a l'autre. L'OS fait ce qu'il veut de la stack dans ton cas. Par exemple OpenBSD reinitialise la frame a 0 dans ce cas la.

    Citation Envoyé par Neckara Voir le message
    Personne ne sait ce que dit le standard C au niveau de l'ABI des appels de fonctions ?
    Le C ne definit pas d'ABI. C'est le compilateur.
    Copier la pile est extremement non portable, car la pile n'as pas la meme ABI suivant les os (stdcall, cdecl) at entre 32/64 bits. Par experience, sur 32 bits, les syscalls passent les parametres par registres (sous Linux), alors que les fonctions passent par la pile, cf: http://docs.cs.up.ac.za/programming/.../syscalls.html
    Sur 64 bits, tout passe par registre. dans ces cas la, tu peux tout copier sur la stack (en gros copier le pushad 32 bits), mais c'est degueu.

Discussions similaires

  1. Réponses: 2
    Dernier message: 11/03/2011, 21h17
  2. Variable dans une fonction appelée par une autre fonction
    Par CyrilD dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 21/12/2010, 13h42
  3. [PHP 5.0] Appel d'une autre fonction de la même classe
    Par Arnaud F. dans le forum Langage
    Réponses: 2
    Dernier message: 11/09/2009, 12h26
  4. Enregistrer des paramètres dans une macro xla
    Par Daejung dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 07/10/2008, 17h29

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