struct ibsm_context;
typedef int (*state)(struct ibsm_context *);
pourquoi etant donne le typdef ci-dessus, je
ne peux pas definir mes fonctions etat de la facon suivante:
state start
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en lieu et place de
int start(struct ibsm_context *context)
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
struct ibsm_context;
typedef int (*state)(struct ibsm_context *);
pourquoi etant donne le typdef ci-dessus, je
ne peux pas definir mes fonctions etat de la facon suivante:
state start
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en lieu et place de
int start(struct ibsm_context *context)
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
struct ibsm_context;
typedef int (*state)(struct ibsm_context *);
pourquoi etant donne le typdef ci-dessus, je
ne peux pas definir mes fonctions etat de la facon suivante:
state start
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en lieu et place de
int start(struct ibsm_context *context)
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en me torturant les meninges sur un automates d'etats, il m'est venu
l'idee tordue suivante: definissant un contexte pour mon automate
struct ibsm_context;
et considerant mes etats comme des fonctions retournant le numero de
l'etat suivant, je definis le type:
typedef int (*state)(struct ibsm_context *);
Ainsi, ayant un tableau associant un etat avec un context:
enum
{
START = 0,
DO_STUFF,
END,
STATE_COUNT
};
state states[] > {
start,
do_stuff,
end
};
Et ma boucle principale ressemble a ca:
void run_automate(void)
{
struct ibsm_context *context = create_context();
int current_state = START;
while (END != (current_state = states[current_state](context)))
/* RIEN ICI */ ;
/* tadam, mon automate a tourne comme il faut... */
}
Maintenant, l'idee tordue: pourquoi etant donne le typdef ci-dessus, je
ne peux pas definir mes fonctions etat de la facon suivante:
state start
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en lieu et place de
int start(struct ibsm_context *context)
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en me torturant les meninges sur un automates d'etats, il m'est venu
l'idee tordue suivante: definissant un contexte pour mon automate
struct ibsm_context;
et considerant mes etats comme des fonctions retournant le numero de
l'etat suivant, je definis le type:
typedef int (*state)(struct ibsm_context *);
Ainsi, ayant un tableau associant un etat avec un context:
enum
{
START = 0,
DO_STUFF,
END,
STATE_COUNT
};
state states[] > {
start,
do_stuff,
end
};
Et ma boucle principale ressemble a ca:
void run_automate(void)
{
struct ibsm_context *context = create_context();
int current_state = START;
while (END != (current_state = states[current_state](context)))
/* RIEN ICI */ ;
/* tadam, mon automate a tourne comme il faut... */
}
Maintenant, l'idee tordue: pourquoi etant donne le typdef ci-dessus, je
ne peux pas definir mes fonctions etat de la facon suivante:
state start
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en lieu et place de
int start(struct ibsm_context *context)
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en me torturant les meninges sur un automates d'etats, il m'est venu
l'idee tordue suivante: definissant un contexte pour mon automate
struct ibsm_context;
et considerant mes etats comme des fonctions retournant le numero de
l'etat suivant, je definis le type:
typedef int (*state)(struct ibsm_context *);
Ainsi, ayant un tableau associant un etat avec un context:
enum
{
START = 0,
DO_STUFF,
END,
STATE_COUNT
};
state states[] > {
start,
do_stuff,
end
};
Et ma boucle principale ressemble a ca:
void run_automate(void)
{
struct ibsm_context *context = create_context();
int current_state = START;
while (END != (current_state = states[current_state](context)))
/* RIEN ICI */ ;
/* tadam, mon automate a tourne comme il faut... */
}
Maintenant, l'idee tordue: pourquoi etant donne le typdef ci-dessus, je
ne peux pas definir mes fonctions etat de la facon suivante:
state start
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
en lieu et place de
int start(struct ibsm_context *context)
{
faire_quelque_chose_avec_le_context(context);
return l_etat_suivant;
}
In 'fr.comp.lang.c', Bertrand Mollinier Toublet
wrote:en me torturant les meninges sur un automates d'etats, il m'est venu
l'idee tordue suivante: definissant un contexte pour mon automate
struct ibsm_context;
et considerant mes etats comme des fonctions retournant le numero de
l'etat suivant, je definis le type:
C'est une façon de faire, pourquoi pas. Ca veut dire que c'est la transition
qui modifie l'état, ce qui ne facilite pas forcément la relecture...
Qu'est ce que tu proposes comme alternative ?
Et ma boucle principale ressemble a ca:
Quelle boucle? En multi-tâche, les automates sont souvent dans une tache. Ils
sont invoqué quand un message (évènement) arrive. La boucle active n'est pas
une fatalité.
Ce n'est pas vraiment une boucle active dans la mesure ou certains etats
void run_automate(void)
{
struct ibsm_context *context = create_context();
int current_state = START;
while (END != (current_state = states[current_state](context)))
/* RIEN ICI */ ;
/* tadam, mon automate a tourne comme il faut... */
Ah? Sans évènements extérieurs? C'est plutôt un bête séquenceur.
Non non, les evenements exterieurs sont pris en charge, dans le contexte
In 'fr.comp.lang.c', Bertrand Mollinier Toublet
<bertrand.molliniertoublet@enst-bretagne.fr> wrote:
en me torturant les meninges sur un automates d'etats, il m'est venu
l'idee tordue suivante: definissant un contexte pour mon automate
struct ibsm_context;
et considerant mes etats comme des fonctions retournant le numero de
l'etat suivant, je definis le type:
C'est une façon de faire, pourquoi pas. Ca veut dire que c'est la transition
qui modifie l'état, ce qui ne facilite pas forcément la relecture...
Qu'est ce que tu proposes comme alternative ?
Et ma boucle principale ressemble a ca:
Quelle boucle? En multi-tâche, les automates sont souvent dans une tache. Ils
sont invoqué quand un message (évènement) arrive. La boucle active n'est pas
une fatalité.
Ce n'est pas vraiment une boucle active dans la mesure ou certains etats
void run_automate(void)
{
struct ibsm_context *context = create_context();
int current_state = START;
while (END != (current_state = states[current_state](context)))
/* RIEN ICI */ ;
/* tadam, mon automate a tourne comme il faut... */
Ah? Sans évènements extérieurs? C'est plutôt un bête séquenceur.
Non non, les evenements exterieurs sont pris en charge, dans le contexte
In 'fr.comp.lang.c', Bertrand Mollinier Toublet
wrote:en me torturant les meninges sur un automates d'etats, il m'est venu
l'idee tordue suivante: definissant un contexte pour mon automate
struct ibsm_context;
et considerant mes etats comme des fonctions retournant le numero de
l'etat suivant, je definis le type:
C'est une façon de faire, pourquoi pas. Ca veut dire que c'est la transition
qui modifie l'état, ce qui ne facilite pas forcément la relecture...
Qu'est ce que tu proposes comme alternative ?
Et ma boucle principale ressemble a ca:
Quelle boucle? En multi-tâche, les automates sont souvent dans une tache. Ils
sont invoqué quand un message (évènement) arrive. La boucle active n'est pas
une fatalité.
Ce n'est pas vraiment une boucle active dans la mesure ou certains etats
void run_automate(void)
{
struct ibsm_context *context = create_context();
int current_state = START;
while (END != (current_state = states[current_state](context)))
/* RIEN ICI */ ;
/* tadam, mon automate a tourne comme il faut... */
Ah? Sans évènements extérieurs? C'est plutôt un bête séquenceur.
Non non, les evenements exterieurs sont pris en charge, dans le contexte
| > Certains compilateurs ont même inventé la syntaxe abominable
| >
| > __attribute__((__unused__))
| >
| > pour annoter des paramètres de fonctions non utilisés. Oui, ça existe
| > et ça sert.
|
| Toi qui t'y connais, mis a part desactiver un warning est ce que gcc
| s'en sert pour autre chose?
Déficience de C qui n'autorise pas de définir une fonction qui ne
s'intéresse pas à son argument. (De plus, il n'y aucune raison
technique à cette interdiction).
Du point de vue du programmeur, c'est une autre histoire.
Imagine une API où
typedef int (*cmd_t)(Context*);
est le type d'une commande prenant un Context* et retournant un int.
(Cela par exemple peut être utiliser dans un interprèt)
cmd_t cmd[256] = {
// ....
};
où, par exemple, cmd['q'] == quit, et quit est défini comme suit
int quit(Context *context)
{
exit(0);
}
c'est typiquement une command qui n'a rien à foutre de son argument.
Des exemples comme cela abondent dans la nature.
Je ne te dis pas ce que cela peut être avec du code automatiquement
généré.
| J'imagine qu'une optimisation dans le code qui
| apelle une telle fonction est possible mais est ce que c'est fait?
pourquoi les gens sautent sur « optimisation » sans passer par la case
« sémantique » ?
| > Certains compilateurs ont même inventé la syntaxe abominable
| >
| > __attribute__((__unused__))
| >
| > pour annoter des paramètres de fonctions non utilisés. Oui, ça existe
| > et ça sert.
|
| Toi qui t'y connais, mis a part desactiver un warning est ce que gcc
| s'en sert pour autre chose?
Déficience de C qui n'autorise pas de définir une fonction qui ne
s'intéresse pas à son argument. (De plus, il n'y aucune raison
technique à cette interdiction).
Du point de vue du programmeur, c'est une autre histoire.
Imagine une API où
typedef int (*cmd_t)(Context*);
est le type d'une commande prenant un Context* et retournant un int.
(Cela par exemple peut être utiliser dans un interprèt)
cmd_t cmd[256] = {
// ....
};
où, par exemple, cmd['q'] == quit, et quit est défini comme suit
int quit(Context *context)
{
exit(0);
}
c'est typiquement une command qui n'a rien à foutre de son argument.
Des exemples comme cela abondent dans la nature.
Je ne te dis pas ce que cela peut être avec du code automatiquement
généré.
| J'imagine qu'une optimisation dans le code qui
| apelle une telle fonction est possible mais est ce que c'est fait?
pourquoi les gens sautent sur « optimisation » sans passer par la case
« sémantique » ?
| > Certains compilateurs ont même inventé la syntaxe abominable
| >
| > __attribute__((__unused__))
| >
| > pour annoter des paramètres de fonctions non utilisés. Oui, ça existe
| > et ça sert.
|
| Toi qui t'y connais, mis a part desactiver un warning est ce que gcc
| s'en sert pour autre chose?
Déficience de C qui n'autorise pas de définir une fonction qui ne
s'intéresse pas à son argument. (De plus, il n'y aucune raison
technique à cette interdiction).
Du point de vue du programmeur, c'est une autre histoire.
Imagine une API où
typedef int (*cmd_t)(Context*);
est le type d'une commande prenant un Context* et retournant un int.
(Cela par exemple peut être utiliser dans un interprèt)
cmd_t cmd[256] = {
// ....
};
où, par exemple, cmd['q'] == quit, et quit est défini comme suit
int quit(Context *context)
{
exit(0);
}
c'est typiquement une command qui n'a rien à foutre de son argument.
Des exemples comme cela abondent dans la nature.
Je ne te dis pas ce que cela peut être avec du code automatiquement
généré.
| J'imagine qu'une optimisation dans le code qui
| apelle une telle fonction est possible mais est ce que c'est fait?
pourquoi les gens sautent sur « optimisation » sans passer par la case
« sémantique » ?
Je suis impatient de la lire.
Je suis impatient de la lire.
Je suis impatient de la lire.
Pour conserver une syntaxe plus consistante, on pourrait overloader void
et introduire au lieu de la premiere version la syntaxe suivante:
int quit(Context *void)
{
exit(0);
}
Qu'en pense tu? M'en vais de ce pas ecrire une proposition au commitee 8>
Tobias
Moi je préfère
int quit(Context *)
{
exit(0);
}
Il faut rappeler que le type void est déjà une abbération en soit, et
qu'il eût été préférable d'écrire :
f()
{
/*...*/
}
au lieu de :
void f(void)
{
/*...*/
}
Expliciter rien est quand même une drôle d'idée.
Pour conserver une syntaxe plus consistante, on pourrait overloader void
et introduire au lieu de la premiere version la syntaxe suivante:
int quit(Context *void)
{
exit(0);
}
Qu'en pense tu? M'en vais de ce pas ecrire une proposition au commitee 8>
Tobias
Moi je préfère
int quit(Context *)
{
exit(0);
}
Il faut rappeler que le type void est déjà une abbération en soit, et
qu'il eût été préférable d'écrire :
f()
{
/*...*/
}
au lieu de :
void f(void)
{
/*...*/
}
Expliciter rien est quand même une drôle d'idée.
Pour conserver une syntaxe plus consistante, on pourrait overloader void
et introduire au lieu de la premiere version la syntaxe suivante:
int quit(Context *void)
{
exit(0);
}
Qu'en pense tu? M'en vais de ce pas ecrire une proposition au commitee 8>
Tobias
Moi je préfère
int quit(Context *)
{
exit(0);
}
Il faut rappeler que le type void est déjà une abbération en soit, et
qu'il eût été préférable d'écrire :
f()
{
/*...*/
}
au lieu de :
void f(void)
{
/*...*/
}
Expliciter rien est quand même une drôle d'idée.
C'est une façon de faire, pourquoi pas. Ca veut dire que c'est la
transition qui modifie l'état, ce qui ne facilite pas forcément la
relecture...
Qu'est ce que tu proposes comme alternative ?
C'est une façon de faire, pourquoi pas. Ca veut dire que c'est la
transition qui modifie l'état, ce qui ne facilite pas forcément la
relecture...
Qu'est ce que tu proposes comme alternative ?
C'est une façon de faire, pourquoi pas. Ca veut dire que c'est la
transition qui modifie l'état, ce qui ne facilite pas forcément la
relecture...
Qu'est ce que tu proposes comme alternative ?