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 :

Fonction de rappel avec pointeur de fonction avec argument


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Par défaut Fonction de rappel avec pointeur de fonction avec argument
    Bonjour,

    J'ai besoin d'implémenter une fonction de rappel (callback function) qui prend en paramètre un pointeur de fonction qui retourne une valeur et prend un paramètre en argument. Hors je ne sais pas à l'avance quel type de paramètre (ni leur nombre) cette fonction va avoir, mais je connais la valeur qui sera toujours retournée.

    Ainsi ceci fonctionne:

    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
    uint16_t fonctionA(uint16_t paramA)
    {
    return paramA;
    }
     
     
    uint16_t fonctionAppellante(uint16_t (*fonctionCalled)(uint16_t),uint16_t param)
    {
    uint16_t resultat;
    resultat = fonctionCalled(param);
    return resultat;
    }
     
    utilisation dans le programme:
    uint16_t var=10;
    result=fonctionAppellante(fonctionA,var);
    Hors cela nécessite de connaitre à l'avance le type et nombre d'argument des fonctions qui seront passées en argument.. et je cherche à utiliser quelque chose de plus générique , comme le ferait un truc dans le genre de mon exemple ci-dessous qui évidement de fonctionne pas:
    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
    uint16_t fonctionA(uint16_t paramA)
    {
    return paramA;
    }
     
     
    uint16_t fonctionAppellante(uint16_t (*fonctionCalled)())
    {
    uint16_t resultat;
    resultat = fonctionCalled();
    return resultat;
    }
     
    utilisation dans le programme:
    uint16_t var=10;
    result=fonctionAppellante(fonctionA(var));

    est ce que quelqu'un a une idée?

    Merci d'avance.

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Salut,

    Avec des pointeurs de type void* et des fonctions à nombre d'arguments variable, tu peux peut-être résoudre ton problème :

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
     
     
    #include <inttypes.h>
    #include <stdio.h> 
    #include <stdarg.h>
     
     
    typedef enum {
    	TypeA,
    	TypeB
    } FonctionType;
    uint16_t fonctionA1(uint16_t paramA)
     
     
    uint16_t fonctionA1(uint16_t paramA){
    	return paramA;
    }
     
    uint16_t fonctionA2(uint16_t paramA){
    	return paramA;
    }
     
     
    uint32_t fonctionB1(uint16_t paramA, uint32_t paramB)
    {
    	return paramA;
    }
     
    uint32_t fonctionB2(uint16_t paramA, uint32_t paramB)
    {
    	return paramA;
    }
     
     
    uint32_t fonctionAppellante(void * callback, FonctionType type, ...){
    	switch(type){
    		case TypeA:
    			{
    				uint16_t (*ptrFunc)(uint16_t paramA);
    				ptrFunc = callback;
     
    				va_list ap;
    				va_start(ap, type);
    					uint16_t paramA;					
    					if(sizeof(paramA) >= sizeof(int)){
    						paramA = va_arg(ap, uint16_t);
    					} else {
    						paramA = va_arg(ap, unsigned int);
    					}
    				va_end(ap);
     
    				return ptrFunc(paramA);
    			}			
    			break;
     
    		case Typeb:
    			{
    				uint32_t (*ptrFunc)(uint16_t paramA, uint32_t paramB);
    				ptrFunc = callback;
     
    				va_list ap;
    				va_start(ap, type);
    					uint16_t paramA;					
    					if(sizeof(paramA) >= sizeof(int)){
    						paramA = va_arg(ap, uint16_t);
    					} else {
    						paramA = va_arg(ap, unsigned int);
    					}
     
    					uint32_t paramB;					
    					if(sizeof(paramB) >= sizeof(int)){
    						paramB = va_arg(ap, uint32_t);
    					} else {
    						paramB = va_arg(ap, unsigned int);
    					}
    				va_end(ap);
     
    				return ptrFunc(paramA, paramB);
    			}			
    			break;
     
     
    		default:
    			break;
     
    	}
     
    	return 0;
    }
     
    // **************************************
     
     
    void main(void){
     
    	uint16_t paramA;
    	uint32_t paramA;
    	uint32_t ret;
     
    	ret = fonctionAppellante(fonctionB1, TypeB, ((uint16_t)1), ((uint32_t)2));
    	printf("val %" PRIu32  "\r\n", ret);
    }

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    - comment tu comptes appeler ta fonction si tu ne sais ni le nombre ni le type des arguments ? c'est un peu casse-gueule
    - tu peux avoir une structure de paramètres qui sera utilisé comme paramètre et tu mets ce que tu veux dedans
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Dans ce cas pourquoi ne pas avoir une fonction générale qui récupère les valeurs en fonction de l'id du capteur ?
    => avoir un truc de la forme :
    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
    19
     
    uint16_t getValue(int capteur_id){
    	switch(capteur_id){
    		case 0:
    		case 2:
    		case 3:
    			return capteur_type1(1, 2, 3);
     
    		case 1:
    		case 8:
    		case 4:
    			return capteur_type2(7, 8);
     
    		default:
    			break;		
    	}
    	return 0;
     
    }
    Aussi, tu peux créer des drivers pour chaque type de capteur qui utilisent les même prototypes (open(), getValue(), close()) et stocker dans chaque drivers les paramètres de configuration de tes drivers (de manière statique ou dynamique).
    Ensuite tu crées un tableau de structures qui fait la liaison entre l'id du capteur, son type, ses paramètres et ses fonctions de callback.

  5. #5
    Membre éclairé Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Par défaut
    Pourquoi ne pas avoir une fonction générale qui récupère les valeurs en fonction de l'id du capteur ?
    en gros c'est ce que j'avais fait au départ.. puis je me suis dit qu'une fonction de rappel éviterai l'usage d'une fonction "intermédiaire" et que ce serait aussi l'occasion de "réviser" la notion de pointeur de fonction (je ne fais pas de dev de façon forcément régulière , donc des fois ça ne fait pas de mal de revoir certains concepts et j'y ai vu l'occasion d'implémenter ce genre de mécanisme.. ..) et c'est là que j'ai rencontré quelques "contraintes"

    dans tout les cas la piqure de (fonction de) rappel ne m'a pas fait de mal

  6. #6
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 768
    Par défaut
    Si tu veux tester, tu peux faire ceci avant de sortir l'artillerie lourde (void* et les ellipses (<- lien wiki en anglais))

    Mais ta structure (qui est un DTO (<- lien wiki en anglais)) risque d'exploser ou d'être modifiée en faisant des tableaux de paramètres par exemple (*) (si tous les paramètres sont du même type).
    Et il ne faut pas te planter lorsque tu charges ta structure ... et d'ailleurs cette structure tu peux en faire un singleton.


    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    // struct is a DTO (Data Transfer Object)
    typedef struct s_params {
        int param1, param2;
        short param3;
    } t_params;
     
    typedef XXX (*t_func) (t_params*);
     
    XXX func_01(t_params* params) {
    //  Use only params->param1
    }
     
    XXX func_02(t_params* params) {
    //  Use params->param2 and params->param3
    }
     
    XXX func_03(t_params* params) {
    //  Use only params->param3
    }
     
     
     
    YYY the_func(t_func func, t_params* params) {
    //  ...
        /*result =*/ func(params);
    //  ...
    }
     
     
    // ...
     
    params.param1 = AAA;
     
    /*result =*/ the_func(func01, &params);
     
     
    params.param2 = BBB;
    params.param3 = CCC;
     
    /*result =*/ the_func(func02, &params);
     
     
    params.param3 = DDD;
     
    /*result =*/ the_func(func03, &params);

    Édit : En y pensant, tu peux créer des fonctions de chargement mutateurs ... facilement convertibles en macros si tu veux de la performance.

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    void params_set_func01_params(t_params* params, int param1) {
    //  if (params != NULL) { // maybe test also param1
            params->param1 = param1;
    //  }
    }
     
    void params_set_func02_params(t_params* params, int param2, short param3) {
    //  if (params != NULL) { // maybe test also param2 and param3
            params->param2 = param2;
            params->param3 = param3;
    //  }
    }
     
    void params_set_func03_params(t_params* params, short param3) {
    //  if (params != NULL) { // maybe test also param3
            params->param3 = param3;
    //  }
    }
     
     
    void params_reset(t_params* params) { // or clear
    // ...
    }
     
    // ...
     
    params_set_func01_params(&params, AAA);
    /*result =*/ the_func(func01, &params);
     
     
    params_set_func02_params(&params, BBB, CCC);
    /*result =*/ the_func(func02, &params);
     
     
    params_set_func03_params(&params, DDD);
    /*result =*/ the_func(func03, &params);

    Édit 1: En y pensant encore, tu peux également créer des accesseurs ... elles aussi facilement convertibles en macros si tu veux de la performance.

    * -> en relisant mon exemple , on peut simplifier la structure en fusionnant les 2 paramètres de types int. Et surtout avec les accesseurs/ mutateurs, cette fusion est transparente.
    Reste à voir comment tu gères cette structure, si tu l'utilises plusieurs fois, .... afin de ne pas avoir de collisions/ pertes de valeurs

  7. #7
    Membre éclairé Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Par défaut
    merci pour ta réponse.

    j'avais pensé passer par un switch en fonction du type dans la fonction appelante.
    Mais je trouve cela dommage car on perd partiellement l’intérêt d'utiliser une fonction de rappel je trouve et cela oblige à connaitre à l'avance l'ensemble des cas de figures (ou du moins à passer en paramètre le nombre d'arguments de chaque type de fonction pour parcourir la va_list).
    En effet, dans ce cas, autant juste avoir un simple parametre en argument et appeler directement la fonction depuis la fonction appelante en fonction de ce paramètre, même si on est d'accord pour des cas où l'on a beaucoup fonctions "structurellement identiques" le mécanisme reste très utile, surtout lorsque la valeur retourné par la fonction appelée peut être différente d'un type de fonction à l'autre.

    Mais dans le cas où , le type de retour est toujours le même, et que seuls les arguments peuvent changer, je ne trouve pas de solution plus "générique" en ne se basant que sur le pointeur vers la fonction . je ne sais pas si je suis clair.. mais en tout cas, visiblement cela n'est pas possible de passer le pointeur vers la fonction et les arguments de la fonction "en même temps" et il faut malgré tout continuer de passer en paramètre de la fonction appelante les arguments de la fonction appelée.


    en tout cas, merci beaucoup pour ton exemple qui me clarifie pas mal de chose pour le coup ^^

    Citation Envoyé par Bousk Voir le message
    - comment tu comptes appeler ta fonction si tu ne sais ni le nombre ni le type des arguments ? c'est un peu casse-gueule
    - tu peux avoir une structure de paramètres qui sera utilisé comme paramètre et tu mets ce que tu veux dedans
    je suis d'accord,.. c'est juste que je suis sur un système embarqué où j'ai des mesures à réaliser, ces mesures sont faites avec des "capteurs différents" qui mesure la même grandeur physique et que les fonctions qui les gèrent renvoient donc toutes le même type de variable mais ont des arguments différents .. et peu importe d'où vient la valeur, ensuite elle est traitée de la même façon.. du coup je souhaitais avoir une seule fonction de traitement, avec en argument la fonction associé au capteur dont je traite l'information...En ayant des fonction sans arguments et en passant ses arguments en variables globales, ça fonctionne mais ce n'est pas terrible.. et ajouter des arguments dans la fonction appelante alors qu'il ne sont utilisés que par la fonction appelé, je trouvais cela dommage aussi.

Discussions similaires

  1. Pointeur fonction avec argument pointeur
    Par hublott dans le forum Débuter
    Réponses: 10
    Dernier message: 11/07/2018, 19h07
  2. onChange et fonction avec arguments
    Par pierre.egaud dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 13/06/2006, 11h02
  3. DLL export de fonction avec argument
    Par slate dans le forum C
    Réponses: 3
    Dernier message: 31/05/2006, 10h36
  4. Fonction callback avec arguments ?
    Par sorry60 dans le forum GTK+ avec C & C++
    Réponses: 39
    Dernier message: 07/11/2005, 10h41
  5. creer une fonction avec arguments
    Par niglo dans le forum ASP
    Réponses: 3
    Dernier message: 03/06/2005, 08h04

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