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 :

Convertir une chaine de caractere en fonction,macro ou identifiant de fonction


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 24
    Points
    24
    Par défaut Convertir une chaine de caractere en fonction,macro ou identifiant de fonction
    Bonjour je suis à la recherche d'une technique ( si elle existe ) qui consiste à exécuter une fonction qu'un utilisateur taperai dans un prompt dans mon programme C.

    Mon problème est que je ne trouve pas de moyen de transformer une chaine de caractère contenant par exemple le mot "mafonction" en fonction mafonction() ou en macro qui appelerai mafonction();

    J'ai essayé plusieurs technique via le préprocesseur mais sans succès, si celui ci permet de transformer un argument en chaine l'inverse lui semble impossible :/.

    Quelqu'un aurait une idée ?

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    184
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 184
    Points : 288
    Points
    288
    Par défaut
    Concernant les macros, faut oublier, car celles-ci disparaissent avant la compilation, donc impossible de les utiliser lors de l'exécution.
    Ensuite, si tu cherches à exécuter un certain ensemble limité de fonctions, tu peux lire le nom de la fonction puis faire des tests avec strcmp genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (strcmp(nom_fonction, "printf") == 0) printf("ursule");
    Sinon, il faut voir du côté de dlopen.
    Le principe, c'est de charger un .so avec dlopen, puis de chercher un symbole par son nom avec dlsym. Dans le cas d'une fonction, tu récupères un pointeur que tu peux ensuite invoquer. C'est ce qui est utilisé pour la création de plug-ins.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 24
    Points
    24
    Par défaut
    merci ,pour la succession de if c'est en effet la technique "naïve" que j'ai implémenté en premier mais il faut se rendre à l'évidence, c'est vraiment très moche quand on à une 50aines de fonctions à tester.

    J'essaie justement de trouver un compromis qui m'éviterais des if à foison.

    Pour dlopen je vais également m'abstenir pour des raisons de standardisation.
    Ce programme est pour un projet étudiant que je dois faire et par conséquent je suis assez limité en champs d'action. C'est tout de même dommage qu'on ne puisse pas transformer une chaine en macro, car j'aurais pu ainsi utiliser un pointeur sur la fonction qui porte le nom "mafonction" via la macro.

  4. #4
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Il n'y a pas de moyen standard en C qui permette d'obtenir l'adresse d'une fonction à l'aide de son nom. Il n'y a pas nom plus de bibliothèque prévu pour ça. C'est du domaine des langages interprétés et déjà ce ne sont pas tous les langages interprétés qui en sont capables.

    Mixer de manière standard du code C et du code écrit dans un langage interprété est possible.

    Il faut que tu nous en dises plus sur le projet si tu veux avoir de "vraies" réponses.

    Jusqu'ici, il n'y a pas d'autre solution que la solution que tu qualifie de "naïve".

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 24
    Points
    24
    Par défaut
    si il n'y a pas de moyen standard sous norme ANSI alors j'utiliserai l'algorithme naïf .

    Le principe du projet est un simple programme C qui lis l'entrée standard et exécute la fonction écrite parmi une liste de fonction autorisé. Ca parait tout simple et ca l'est via un simple scanf("%s",machaine), juste que lorsque l'on a beaucoup de fonctions la succession de if rend le code très "brut" et péniblement lisible selon moi je recherchais donc une façon de généraliser cette portion de code.

  6. #6
    Membre éclairé Avatar de Bayard
    Inscrit en
    Juin 2002
    Messages
    861
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 861
    Points : 716
    Points
    716
    Par défaut
    Il y a également la possibilité d'utiliser l'interpréteur de commande python.
    Il est peut être "lourd" d'interfacer python avec le C, mais cela se fait assez bien.
    De nombreuses solutions existent.
    Au cas où: http://www.python.org
    prendre la version 2.6 et non pas 3.X
    L'interpréteur de commande s'appelle IDLE.

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    184
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 184
    Points : 288
    Points
    288
    Par défaut
    Bonjour,
    je te propose un truc dans ce goût là :
    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
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
     
    #define APPEL_FONCTION(buffer, nom, ...) if (strcmp(buffer, #nom) == 0) nom(__VA_ARGS__);
     
    int main(void) {
    	char buffer[50];
     
    	if (fgets(buffer, 49, stdin) == NULL) {
    		perror("fgets");
    		return EXIT_FAILURE;
    	}
     
    	/* Je supprime le saut de ligne, mais il y a d'autres options */
    	for (int i = 0; buffer[i] != 0; i++) buffer[i] = buffer[i] != '\n' ? buffer[i] : '\0';
     
    	APPEL_FONCTION(buffer, printf, "essai de la fonction printf\n");
    	APPEL_FONCTION(buffer, fprintf, stderr, "essai de la fonction fprintf\n");	
     
    	return EXIT_SUCCESS;
    }
    La question, c'est que se passe-t-il au niveau des arguments ? Il sont connus avant ? Quelle est la liste des fonctions autorisées ? Ont-elles une signature commune ?

    [Edit] je viens de retrouver ça : TCC.
    C'est un compilateur C, mais qui propose également un interpréteur (ce que tu cherches à coder). Il faudrait voir un peu dans les sources, si elles sont pas illisibles comment ça fonctionne, mais je soupçonne du dlopen... Mais tout espoir n'est pas perdu puisque qu'il fonctionne aussi sous win .

  8. #8
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    J'ai déjà eu affaire à un cas similaire avec un petit interpréteur, renseignes toi sur ce qu'est les «jumps tables», voici un petit exemple pour illustrer le principe :
    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
    #include  <stdio.h>
    #include  <stdlib.h>
    #include  <string.h>
     
    #define  NELEM(t) 	(sizeof(t)/sizeof(t[0]))
     
    typedef struct 
    {
    	char name[32];
    	void (*call) (void);
    }function;
     
    void Big_Mac( void );
    void Cheeseburger( void );
    void Royal_Bacon( void );
    void Big_Tasty( void );
    void Royal_O_Fish( void );
    int compar(const void *val1, const void *val2);
     
    int main( void )
    {
    	size_t i;
    	char functionName[32];
    	/* Liste des fonctions triee par ordre alphabétique */
    	function functions[] = { { "Big_Mac"		, Big_Mac	},
    				 { "Big_Tasty"		, Big_Tasty	},
    				 { "Cheeseburger"	, Cheeseburger	},
    				 { "Royal_Bacon"	, Royal_Bacon	},
    				 { "Royal_O_Fish"	, Royal_O_Fish	} };
     
    	for( i=0 ; i<NELEM(functions) ; i++ ) {
    		puts(functions[i].name);
    	}
    	printf("Faites votre choix : "); fflush(stdout);
     
    	/* Lecture du nom de la fonction a appeler */
    	if( fgets(functionName, sizeof functionName, stdin)!=NULL) {
    		char *nl;
    		function *match;
    		/* Suppression du '\n' */
    		if( (nl = strchr(functionName, '\n'))!=NULL) {
    			*nl = '\0';
    		}
    		/* Recherche ... */
    		match = bsearch(functionName, functions, NELEM(functions), sizeof *functions, compar);
     
    		if( match!=NULL ) {
    			match->call();
    		} else {
    			puts("Aucune correspondance trouvee");
    		}
    	}
     
    	return 0;
    }
     
    int compar(const void *val1, const void *val2)
    {
    	const function *func1 = val1;
    	const function *func2 = val2;
     
    	return strcmp(func1->name, func2->name);
    }
     
    void Big_Mac( void )
    {
    	puts("talon inférieur Mac, sauce Mac, oignons reconstitués, laitue émincée, tranc"
    	     "he de fromage, pâté de boeuf régulier (10:1), talon supérieur Mac, sauce Ma"
    	     "c, oignons reconstitués, laitue émincée, cornichons (x2), pâté de boeuf rég"
    	     "ulier (10:1), couronne Mac.");
    }
     
    void Cheeseburger( void )
    {
    	puts("couronne sans sésame, moutarde, ketchup, oignons reconstitués, cornichon, t"
    	     "ranche de fromage, pâté de boeuf régulier (10:1), talon.");
    }
     
    void Royal_Bacon( void )
    {
    	puts("couronne avec sésame, moutarde, ketchup, oignons en lamelles, cornichons (x"
    	     "2), tranche de fromage, pâté de boeuf(4:1), tranche de fromage, talon, avec"
    	     " 2 tranches de bacon entre les cornichons et le pâté de boeuf(4:1).");
    }
     
    void Big_Tasty( void )
    {
    	puts("couronne large, sauce grillée, oignons en lamelles, salade Tasty, tranches "
    	     "de tomate (x2), tranche de fromage emmental (ou de bacon), pâté de boeuf la"
    	     "rge (3:1), tranches de fromage emmental (x2), talon large.");
    }
     
    void Royal_O_Fish( void )
    {
    	puts("couronne avec sésame, sauce tomate avec du persil, laitue émincée, tranche "
    	     "de tomate (x1), patty Filet, talon.");
    }
    Tu peux toutefois essayer avec un grand switch, dans la plupart des cas le compilateur le transformera automatiquement en une jump table.

    Bonne appétit.

  9. #9
    Membre expérimenté
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    952
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

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

    Informations forums :
    Inscription : Mars 2006
    Messages : 952
    Points : 1 351
    Points
    1 351
    Par défaut
    Salut,
    Citation Envoyé par huit_six Voir le message
    La question, c'est que se passe-t-il au niveau des arguments ? Il sont connus avant ? Quelle est la liste des fonctions autorisées ? Ont-elles une signature commune ?
    Pour avoir écrit plusieurs interpréteurs de ce type, je dirai que ce n'est pas sorcier à résoudre dans le principe. Il ne faut écrire que des fonctions int myfunc(void), l'int de retour de la fonction étant un code d'erreur. Les commandes (c'est plus parlant que "fonctions") extrayant chacune leurs paramètres de la ligne de commande.

    L'interpréteur se résume donc à une table de structures contenant les noms des commandes et les pointeurs de type int myfunc(void), plus quelques fonctions basiques d'extraction de paramètres de la ligne de commande.

    La commande d'interprétation elle même ne fait que comparer le premier mot de la ligne de commande avec le nom des commandes dans la table de structure, appeler la commande si correspondance du nom, et gestion des erreurs au retour: Commande inconnue, mauvais paramètres, etc... Les autres mots de la ligne de commande sont les paramètres.

    A+

    Pfeuh

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 39
    Points : 24
    Points
    24
    Par défaut
    Citation Envoyé par ssmario2 Voir le message
    J'ai déjà eu affaire à un cas similaire avec un petit interpréteur, renseignes toi sur ce qu'est les «jumps tables», voici un petit exemple pour illustrer le principe :
    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
    #include  <stdio.h>
    #include  <stdlib.h>
    #include  <string.h>
     
    #define  NELEM(t) 	(sizeof(t)/sizeof(t[0]))
     
    typedef struct 
    {
    	char name[32];
    	void (*call) (void);
    }function;
     
    void Big_Mac( void );
    void Cheeseburger( void );
    void Royal_Bacon( void );
    void Big_Tasty( void );
    void Royal_O_Fish( void );
    int compar(const void *val1, const void *val2);
     
    int main( void )
    {
    	size_t i;
    	char functionName[32];
    	/* Liste des fonctions triee par ordre alphabétique */
    	function functions[] = { { "Big_Mac"		, Big_Mac	},
    				 { "Big_Tasty"		, Big_Tasty	},
    				 { "Cheeseburger"	, Cheeseburger	},
    				 { "Royal_Bacon"	, Royal_Bacon	},
    				 { "Royal_O_Fish"	, Royal_O_Fish	} };
     
    	for( i=0 ; i<NELEM(functions) ; i++ ) {
    		puts(functions[i].name);
    	}
    	printf("Faites votre choix : "); fflush(stdout);
     
    	/* Lecture du nom de la fonction a appeler */
    	if( fgets(functionName, sizeof functionName, stdin)!=NULL) {
    		char *nl;
    		function *match;
    		/* Suppression du '\n' */
    		if( (nl = strchr(functionName, '\n'))!=NULL) {
    			*nl = '\0';
    		}
    		/* Recherche ... */
    		match = bsearch(functionName, functions, NELEM(functions), sizeof *functions, compar);
     
    		if( match!=NULL ) {
    			match->call();
    		} else {
    			puts("Aucune correspondance trouvee");
    		}
    	}
     
    	return 0;
    }
     
    int compar(const void *val1, const void *val2)
    {
    	const function *func1 = val1;
    	const function *func2 = val2;
     
    	return strcmp(func1->name, func2->name);
    }
     
    void Big_Mac( void )
    {
    	puts("talon inférieur Mac, sauce Mac, oignons reconstitués, laitue émincée, tranc"
    	     "he de fromage, pâté de boeuf régulier (10:1), talon supérieur Mac, sauce Ma"
    	     "c, oignons reconstitués, laitue émincée, cornichons (x2), pâté de boeuf rég"
    	     "ulier (10:1), couronne Mac.");
    }
     
    void Cheeseburger( void )
    {
    	puts("couronne sans sésame, moutarde, ketchup, oignons reconstitués, cornichon, t"
    	     "ranche de fromage, pâté de boeuf régulier (10:1), talon.");
    }
     
    void Royal_Bacon( void )
    {
    	puts("couronne avec sésame, moutarde, ketchup, oignons en lamelles, cornichons (x"
    	     "2), tranche de fromage, pâté de boeuf(4:1), tranche de fromage, talon, avec"
    	     " 2 tranches de bacon entre les cornichons et le pâté de boeuf(4:1).");
    }
     
    void Big_Tasty( void )
    {
    	puts("couronne large, sauce grillée, oignons en lamelles, salade Tasty, tranches "
    	     "de tomate (x2), tranche de fromage emmental (ou de bacon), pâté de boeuf la"
    	     "rge (3:1), tranches de fromage emmental (x2), talon large.");
    }
     
    void Royal_O_Fish( void )
    {
    	puts("couronne avec sésame, sauce tomate avec du persil, laitue émincée, tranche "
    	     "de tomate (x1), patty Filet, talon.");
    }
    Tu peux toutefois essayer avec un grand switch, dans la plupart des cas le compilateur le transformera automatiquement en une jump table.

    Bonne appétit.
    Un grand merci à toi ! les jumps tables en effet c'est magique, ce n'est ni plus ni moins qu'une table de hashage de pointeurs de fonctions (quand c'est bien fait).
    On a donc le code extrêmement réduit et un code optimisé par le compilateur quand il est assemblé.
    Pour ce que ca intéresserai voici un peu de documentation.
    ici
    L'exemple ce base sur du code pour systèmes embarquées mais il est tout aussi valable pour n'importe quel système ou le développeur et un temps soit peu soucieux de bien faire son travail .

Discussions similaires

  1. Réponses: 3
    Dernier message: 18/10/2009, 11h31
  2. Réponses: 3
    Dernier message: 15/08/2007, 14h52
  3. Réponses: 11
    Dernier message: 08/06/2007, 20h19
  4. convertir une chaine de caractere en byte []
    Par youp_db dans le forum Langage
    Réponses: 10
    Dernier message: 16/10/2006, 15h14
  5. [VB]Convertir une chaine de caractere en entier
    Par budylove dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 21/02/2006, 11h06

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