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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    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.
    Stay a while and listen...

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

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    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 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    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 habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    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.
    Stay a while and listen...

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    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.

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    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
    Stay a while and listen...

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    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 630
    Points : 10 556
    Points
    10 556
    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

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Tu ne peux pas faire du C++ à tout hasard ?

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Après si on veut vraiment passer sur une solution modulaire et facile à faire évoluer, je partirai sur ce type de solution :


    main.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
    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
     
    #include "driver_sonde.h"
    #include "wrapper_sondeType1.h"
    #include "wrapper_sondeType2.h"
     
    // ********************
    // Réservation de l'espace mémoire utile
     
    #define INTERFACE_COUNT	(3)
    static SONDE_INTERFACE interfaceList[INTERFACE_COUNT];
     
    static SONDE_STRUCT driverSonde0 = {
    	.read = wrapper_sondeType1_read
    }
    static SONDE_TYPE1_CONTEXT contextSonde0;
     
    static SONDE_STRUCT driverSonde1 = {
    	.read = wrapper_sondeType1_read
    }
    static SONDE_TYPE1_CONTEXT contextSonde1;
     
    static SONDE_STRUCT driverSonde2 = {
    	.read = wrapper_sondeType2_read
    }
    static SONDE_TYPE2_CONTEXT contextSonde2;
     
     
    void main(void){
     
    	// ********************
    	// Configuration
    	SONDE_INTERFACE * interface;
     
    	interface = getInterface(0);
    	strcpy(interface->name, "SONDE0");
    	sonde_SetInterface(interface, &driverSonde0, &contextSonde0);
     
    	interface = getInterface(1);
    	strcpy(interface->name, "SONDE1");
    	sonde_SetInterface(interface, &driverSonde1, &contextSonde1);
     
    	interface = getInterface(2);
    	strcpy(interface->name, "SONDE2");
    	sonde_SetInterface(interface, &driverSonde2, &contextSonde2);
     
     
     
    	// ********************
    	// Utilisation
    	uint16_t val;
     
    	while(1){
    		interface = getInterface(0);
    		sonde_Read(interface, &val);
    		printf("Sonde %s : %" PRIu16 "\r\n", interface->name, val);
     
    		interface = getInterface(1);
    		sonde_Read(interface, &val);
    		printf("Sonde %s : %" PRIu16 "\r\n", interface->name, val);
     
    		interface = getInterface(2);
    		sonde_Read(interface, &val);
    		printf("Sonde %s : %" PRIu16 "\r\n", interface->name, val);
    	}
     
    }
     
    SONDE_INTERFACE* getInterface(int id){
    	return &interfaceList[id];
    }

    driver_sonde.h/.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
    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
     
    // *********************************
    // driver_sonde.h
     
    typedef enum {
    	NO_ERROR = 0,
    	ERROR_BUSY,
    	ERROR_UNDECLARED
    	//...
    } error_t;
     
    typedef error_t (*SONDE_READ)(void *context, uint16_t *val);
     
    typedef struct {
       SONDE_READ read;
    } SONDE_STRUCT;
     
    typedef struct {
    	char name[10];
    	const SONDE_STRUCT * driver;
    	void *context;
    	// ...
    } SONDE_INTERFACE;
     
     
     
    error_t sonde_SetInterface(SONDE_INTERFACE *interface, const SONDE_STRUCT *driver);
    error_t sonde_Read(SONDE_INTERFACE *interface, uint16_t * val);
     
     
     
    // *********************************
    // driver_sonde.c
    #include "driver_sonde.h"
     
    error_t sonde_SetInterface(SONDE_INTERFACE *interface, const SONDE_STRUCT *driver, void * context){
    	interface->driver = driver;
    	interface->context = context;
    	return NO_ERROR;
    }
     
    error_t sonde_Read(SONDE_INTERFACE *interface, uint16_t * val){
    	interface->read(interface->context, val);
    	return NO_ERROR;
    }

    wrapper_sondeType1.h/.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
    19
    20
    21
    22
    23
     
    // *********************************
    // wrapper_sondeType1.h
    #include "driver_sonde.h"
     
    typedef struct{
    	uint16_t param1;
    	uint16_t param2;
    } SONDE_TYPE1_CONTEXT;
     
    error_t wrapper_sondeType1_read(void *context, uint16_t *val);
     
     
    // *********************************
    // wrapper_sondeType1.c
    #include "wrapper_sondeType1.h"
    #include "sondeType1.h"
     
    error_t wrapper_sondeType1_read(void *context, uint16_t *val){
    	SONDE_TYPE1_CONTEXT * params = (SONDE_TYPE1_CONTEXT*)context;
    	*val = sondeType1_read(params->param1, params->param2);
    	return NO_ERROR;
    }

    sondeType1.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    uint16 sondeType1_read(uint16_t param1, uint16_t param2);


    wrapper_sondeType2.h/.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
    19
    20
    21
    22
     
    // *********************************
    // wrapper_sondeType2.h
    #include "driver_sonde.h"
     
    typedef struct{
    	uint32_t param1;
    } SONDE_TYPE2_CONTEXT;
     
    error_t wrapper_sondeType2_read(void *context, uint16_t *val);
     
     
    // *********************************
    // wrapper_sondeType2.c
    #include "wrapper_sondeType2.h"
    #include "sondeType2.h"
     
    error_t wrapper_sondeType2_read(void *context, uint16_t *val){
    	SONDE_TYPE2_CONTEXT * params = (SONDE_TYPE2_CONTEXT*)context;
    	*val = sondeType2_read(params->param1);
    	return NO_ERROR;
    }
    sondeType2.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    uint16 sondeType2_read(uint32_t param1);

    => On peut facilement ajouter des fonctions d'initialisation/configuration des drivers, de nouveaux paramètres et gérer des semaphores.

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Salut tout le monde,

    Désolé pour le temps de réponse.

    ha oui, en effet, c'est bien intéressant, et ça montre aussi que ce que je pensais être possible de faire au départ est finalement plus compliqué que je ne l'aurait cru.

    boboss123, j'avoue que je n'ai pas tout compris à ton exemple, peux tu s'il te plait en expliquer la "philosophie"?

    foetus, j'avais pensé à créer des accesseurs ^^ mais pour mon projet ça revient à vraiment complexifier le truc.. ma question étant aussi là pour apprendre/comprendre car même si ce n'est pas le cas sur mon projet actuel, j'ai entrevue des problématiques potentielles dans de futurs projets..

    bktero, en c++ sur du petit microcontrôleur.. c'est sur que c'est faisable, mais j'avoue que j'ai toujours développé en C pour de l'embarqué sur micro, réservant en général le C++ (avec Qt) pour des interfaces graphiques sur pc.
    Stay a while and listen...

  11. #11
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Il ne faut pas bannir le C++ sous prétexte que tu fais de l'embarqué sur MCU J'ai du C++ pendant presque 3 ans sur Cortex-M en pro et j'ai déjà fait des essais en perso sur du MSP430.

    En C++, il y a des features qui coûtent et d'autres qui ne coûtent rien. Et parmi les trucs qui ne coûtent rien, il y a des trucs super chouettes ! De manière absolument pas exhaustive :
    - Les classes avec la visibilité public / privé
    - L'héritage sans virtualité
    - Les namespaces
    - Les templates
    - La surcharge de fonctions

    De plus, la bibliothèque standard est carrément plus fournie que celle du C. Par exemple, tu as une palette bien fournie d'algorithmes avec #include <algorithm>.

    La surcharge te permet par exemple de faire des trucs comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int readTemperature(int*) {
        return 0;
    }
     
    int readTemperature(int, int) {
        return 1;
    }
     
    int main() {
        auto a = readTemperature(nullptr);
        auto b = readTemperature(42, 666);
     
        return a + b;
    }
    Sur quelle cible programmes-tu ? Quelle est ta toolchain ?

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    ha oui, en effet, avec la surcharge, ça réponds facilement à la question ..

    je suis sur dspic33 avec le compilateur XC16 .. de mémoire ce n'est pas compatible C++ et pas sur que l'architecture le soit non plus.
    Stay a while and listen...

  13. #13
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Ah Microchip.....

    Tu n'auras pas de C++, il faudrait avoir le compiler XC32 : https://www.microchip.com/mplab/compilers

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    oui en effet, mais là on change de cible.

    HS: pourquoi "Ah Microchip....." raconte ... ^^
    Stay a while and listen...

  15. #15
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    [HS]
    On dira que Microchip n'a pas forcément toujours bonne presse, en tout cas pour leur MCU.

    J'ai eu une mauvaise expérience en perso sur un projet maison. C'était du PIC16 avec Mplab 8 et le vieux compilateur qui allait avec. L'IDE est minable (comparé à MSP430 qui a la même époque avec du GCC et du Eclipse), le compilateur tout nul (son seul message d'erreur c'était "syntax error"... tellement pénible que je faisais compiler avec GCC et des stubs de *.h pour avoir des messages clairs). J'ai eu un bug sur ce MCU où la désactivation des external interrupts ne fonctionnait pas. Génial quand ton but c'est de gérer des boutons poussoirs. Du coup, dans la fonction d'interruption tu testes le flag pour traiter ou pas l'IT. Génial, hein ?

    En perso encore, j'ai voulu faire du PIC12. Il n'y avait pas de compilateur C. Je n'ai pas utilisé mes PIC12, la flemme d'apprendre leur ASM pour faire clignoter 3 LED. Après, j'aurais pu le savoir à l'avance, c'est ma faute...

    En pro, j'ai utilisé en stage il y a longtemps, j'étais pas encore un dev aguerri, je me souviens plus trop. Par contre, j'ai eu plein d'échos négatifs : compilateurs bogués, bug de puces, erratas dans tous les sens, etc. J'ai eu un collègue qui détestaient cette marque, c'était un running gag

    De manière générale, leurs MCU ne sont pas (n'étaient pas ?) pensé pour être programmés en C.
    - A titre d'exemple, sur PIC16, tu as 2 interruptions : low et high. Après débrouille toi pour tester qui a généré l'interruption. Et attention ! Il faut des fonctions ultra courtes à ces emplacements mémoires sinon la première écrase la 2e sans crier gare. Il faut le savoir, c'est tout. On est très très loin de la simplicité sur MSP430 ou des Cortex-M.
    - J'ai aussi souvent lu que la gestion de la stack était... "minimaliste", ce qui est difficilement compatible avec un langage comme le C. Voir par exemple :

    Nom : pic1.PNG
Affichages : 172
Taille : 61,4 Ko

    Nom : pic2.PNG
Affichages : 228
Taille : 122,9 Ko

    [/HS]

  16. #16
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Je bosse pas mal sur Microchip, ils ont quand même pas mal évolué :
    - Le nouveau IDE (basé sur NetBeans) n'a plus rien à voir avec MPLAB 8
    - Les µControleurs PIC32 (architectures MIPS32) utilise un compilateur basé sur GCC (je ne sais pas si les 8 et 16 bits sont actuellement sur GCC).
    - J'ai fait pas mal de programmes sur PIC18 en C, je n'ai jamais eu trop de soucis.
    - Ils ont racheté Atmel : ils ont donc maintenant des contrôleurs avec MPU basés sur architecture ARM.
    - Ils ont aussi racheté Microsemi (fabricant de composants Ethernet) et Micrel (mémoires).
    => Les architectures des µControleur 32-bits n'ont plus rien à voir avec les anciennes architectures

    Après ça ne les empêchent pas de vendre des µControleurs bugués : sur certains modèle de PIC32, les périphérique I2C fonctionnent mal, et certaines entrées d'horloges ne fonctionne tout simplement pas dans certains modes...
    => mais chez les autres fabricants, il y a surement le même genre de problèmes (toujours lire les errata d'un composant avant de le choisir).

    Coté logiciel, il fournissent pas mal de choses en gratuit mais leur suite logiciel Harmony est un peu une usine à gaz.
    Et il y a peu de documentation sur l'utilisation de leur µControleur avec des logiciels libres (ex: FreeRTOS avec PIC32)... mais avec le rachat d'Atmel, ça va surement changer vu qu'ils ont maintenant des µControleur sur architecture ARM (pas encore testé).

  17. #17
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Citation Envoyé par zodd Voir le message
    boboss123, j'avoue que je n'ai pas tout compris à ton exemple, peux tu s'il te plait en expliquer la "philosophie"?
    Pour chaque type de sonde, je défini des fonctions qui ont le même prototype. Comme paramètre d'entrée, j'ai un pointeur de type void * qui permet de pointer sur une structure qui dépend de la sonde utilisée : la fonction caste dans le bon type le pointeur (ex : SONDE_TYPE1_CONTEXT) et ensuite appelle la fonction de lecture associée à la sonde (ex : sondeType1_read()) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error_t wrapper_sondeTypeX_read(void *context, uint16_t *val);

    Ensuite la structure SONDE_INTERFACE permet de faire le lien entre les différents fonctions du drivers et le contexte d’exécution.

  18. #18
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Je suis d'accord avec toi bobos123, je pense que ça change. Je ne l'ai pas vu directement mais quelques éléments me mettent sur cette piste :
    - l'arrivée de MPLAB-X, même j'aurais plus vu une base Eclipse que NetBeans
    - le rachat d'Atmel qui ramène pas mal de MCU type Cortex-M
    - tu parles de GCC et ça aussi c'est du positif
    Ce vécu dont je parle commence à avoir 3, 4 ou 5 ans, il est normal qu'ils corrigent le tir, notamment sur les architectures de MCU !

    Pour ce qui est des erratas et des bugs de puces : oui, oui les autres en font aussi !

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    merci boboss123 pour les éclaircissement, super astucieux.. je reprendrai cela à tête reposé pour bien le digérer car là je suis dans le jus un fer à soudé à la main.. ^^

    pour revenir au HS : sur microchip, en effet j'ai aussi expérimenter par le passé de nombreux des soucis d'erratas, mais les autres aussi ont leurs soucis.. le réflexe étant de lire les erratas avant de choisir le micro du coup une fois qu'on s'est fait avoir..
    Pour ce qui est de la mémoire, en effet, sur les 8 bits, ça pouvait vite devenir un arrachage de cheveux et il fallait (avant l'arrivée des nouveaux compilo) se farcir la doc du compilateur pour avoir recours à leurs pragma dédiés quand nécessaires, etc.. .. mais depuis leur nouvelle gamme de compilateur XC (qui est basé sur gcc je crois) n'a plus rien à voir avec l'ancienne.. c'est vraiment le jour et la nuit.. NetBeans aussi est vraiment pas mal.. je bosse aussi un peu sur des micro TI avec Code Composer Studio qui est en fait Eclipes, et je trouve que les deux IDE sont quand même sympa et pratiques .. mais j'avoue que les outils TI (avec tout leurs projets d'exemple, etc) sont mieux intégrés .. cela dit les dspic33, quand on les connait bien permettent vraiment d'aller "vite au résultat". Harmony pour PIC32, perso, j'ai jamais réussit à m'en servir correctement.. mais l'idée est bonne, j'espère qu'ils vont réussir à le rendre vraiment pratique à utiliser (et sans bugs)..
    Stay a while and listen...

  20. #20
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Le problème d'Harmony est qu'il ont voulu créer une interface graphique pour activer/désactiver les différents modules et donc dès que tu veux ajouter ton propre module, ou n'utiliser que les drivers bas niveau ou créer une board qui ne fait pas partie des modèles fournis, c'est un peu le bazard car c'est peu documenté (mais ça se fait).
    => le principe est pas mal dans l'idée mais ils n'ont pas poussé l'idée assez loin (certains drivers ne sont pas terminés/disponible et les dépendences entre les modules sont mal gérée... difficile de trouver la bonne configuration... on final, il faut lire le code source des modules... et donc on perd l'interêt de l'interface de configuration graphique).

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