Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Insérer une fonctions dans une structure?

27 réponses
Avatar
frederic
Bonjour,

y-a-t'il moyen en C, d'insérer une ou des fonctions dans une structure de données?

typedef struct Complex Complex;
struct Complex {
int value;
int (*fn)();
char *mesg;
};

Lorsque je compile comme ça, le compilo ne cris pas, mais par
contre, il hurle si j'ai la déclaration suivante:

Complex table[] = {
ONE, double(ONE), "premier message",
TWO, double(TWO), "deuxième message",
THREE, double(TREE), "troisième message",
FOUR, double(FOUR), "quatrième message",
};

pour info:
int double(int i)
{
return i * i;
}

enum {
ONE = 10,
TWO,
THREE,
FOUR,
};
--
Frédéric

10 réponses

1 2 3
Avatar
Harpo
wrote:

Lorsque je compile comme ça, le compilo ne cris pas, mais par
contre, il hurle


Moi aussi ça m'arrive de hurler, ça défoule.
Poste un programme minimal, ce sera plus simple pour tout le monde.

Avatar
Pierre Habouzit
int (*fn)();
ceci est un pointeur sur une fonction qui prend aucun argument et renvoie un

entier.

ONE, double(ONE), "premier message",


double(ONE) est un entier. pas un pointeur sur fonction.

pour info:
int double(int i)
{
return i * i;
}


double est très mal nommée, elle devrait s'appeler square (ou carre).
d'autant plus que double est un type à virgule flottante.

--
·O· Pierre Habouzit
··O
OOO http://www.madism.org

Avatar
Emmanuel Delahaye
y-a-t'il moyen en C, d'insérer une ou des fonctions dans une structure de données?


Non, et ce serait absurde de multiplier le code à chaque instance... Les
principes OO de programmation 'moderne' consistent à ecrire (et
instancier) le code une fois, mais d'instancier les données autant de
fois que l'on veut. Certainement pas d'avoir plusieurs instance du même
code. Ce serait inutile et couteux...

typedef struct Complex Complex;
struct Complex {
int value;
int (*fn)();


Ca, c'est autre chose. C'est un pointeiur sur une fonction dont le code
est 'ailleurs'.

Cette façon de procéder répond au principe énoncé ci-dessus, à savoir
une instance du code pour n instances des données (dont les pointeurs de
fonction pointent toutes sur le même code)

char *mesg;
};

Lorsque je compile comme ça, le compilo ne cris pas, mais par
contre, il hurle si j'ai la déclaration suivante:

Complex table[] = {
ONE, double(ONE), "premier message",


Evidemment. Ici, on ne fait pas d'appel, mais de définition de structure
avec initialisation. Seul le nom de la fonctiohn doit être utilisé.

ONE, double, "premier message",
etc.

Nota. C'est pas une bonne iddée d'utiliser 'double' pour un nom de
fonction, vu que c'est le nom d'un type du langage.

Avatar
Pierre Maurette
Bonjour,

y-a-t'il moyen en C, d'insérer une ou des fonctions dans une structure de
données?

typedef struct Complex Complex;
struct Complex {
int value;
int (*fn)();
char *mesg;
};
Oui, c'est possible, c'est même facile. Vous aviez bien commencé. Ce

qui reste à faire, c'est initiliser et utiliser les membres fn de vos
structures.
Le plus simple pour initialiser C.fn, c'est de lui affecter l'adresse
d'une fonction fonct. On peut pour cela utiliser indifféremment fonct
ou &fonct. Cette facilité - que je trouve regrettable, mais c'est un
troll - n'est pas unique dans le langage.
Un code de test pourrait être (OK, le style est à chier):

int carre(int i) {return i * i;}
int cube(int i) {return i * i * i;}

enum {ONE = 10, TWO};

Complex table[] = {
ONE, &cube, "premier message",
TWO, &carre, "deuxième message",
};

printf("%dt%dt%sn", table[0].value, table[0].fn(table[0].value),
table[0].mesg);
printf("%dt%dt%sn", table[1].value, table[1].fn(table[1].value),
table[1].mesg);

Comme plusieurs fois signalé, soyez prudent avec les nommages. double
doit être proscrit, et je n'aime pas trop Complex dans ce contexte.

--
Pierre Maurette

Avatar
frederic
"Pierre Maurette" writes:

Bonjour,

y-a-t'il moyen en C, d'insérer une ou des fonctions dans une structure
de données?

typedef struct Complex Complex;
struct Complex {
int value;
int (*fn)();
char *mesg;
};
Oui, c'est possible, c'est même facile. Vous aviez bien commencé. Ce qui

reste à faire, c'est initiliser et utiliser les membres fn de vos
structures.
Le plus simple pour initialiser C.fn, c'est de lui affecter l'adresse
d'une fonction fonct. On peut pour cela utiliser indifféremment fonct ou
&fonct. Cette facilité - que je trouve regrettable, mais c'est un troll
- n'est pas unique dans le langage.
Un code de test pourrait être (OK, le style est à chier):

int carre(int i) {return i * i;}
int cube(int i) {return i * i * i;}

enum {ONE = 10, TWO};

Complex table[] = {
ONE, &cube, "premier message",
TWO, &carre, "deuxième message",
};

printf("%dt%dt%sn", table[0].value, table[0].fn(table[0].value),
table[0].mesg);
printf("%dt%dt%sn", table[1].value, table[1].fn(table[1].value),
table[1].mesg);

Comme plusieurs fois signalé, soyez prudent avec les nommages. double
doit être proscrit, et je n'aime pas trop Complex dans ce contexte.


Ok je comprends mieux merci. Mais je voulais savoir si il n'y a pas
moyen de le faire plutôt pour une fonction quelconque de type void?

En ce qui concerne le 'double' effectivement le nom est mal donné, mais
il s'agissait juste d'expérimenter une fn dans uns structure....

--
Frédéric


Avatar
Pierre Maurette
"Pierre Maurette" writes:

Bonjour,

y-a-t'il moyen en C, d'insérer une ou des fonctions dans une structure
de données?

typedef struct Complex Complex;
struct Complex {
int value;
int (*fn)();
char *mesg;
};
Oui, c'est possible, c'est même facile. Vous aviez bien commencé. Ce qui

reste à faire, c'est initiliser et utiliser les membres fn de vos
structures.
Le plus simple pour initialiser C.fn, c'est de lui affecter l'adresse
d'une fonction fonct. On peut pour cela utiliser indifféremment fonct ou
&fonct. Cette facilité - que je trouve regrettable, mais c'est un troll
- n'est pas unique dans le langage.
Un code de test pourrait être (OK, le style est à chier):

int carre(int i) {return i * i;}
int cube(int i) {return i * i * i;}

enum {ONE = 10, TWO};

Complex table[] = {
ONE, &cube, "premier message",
TWO, &carre, "deuxième message",
};

printf("%dt%dt%sn", table[0].value, table[0].fn(table[0].value),
table[0].mesg);
printf("%dt%dt%sn", table[1].value, table[1].fn(table[1].value),
table[1].mesg);

Comme plusieurs fois signalé, soyez prudent avec les nommages. double
doit être proscrit, et je n'aime pas trop Complex dans ce contexte.


Ok je comprends mieux merci. Mais je voulais savoir si il n'y a pas
moyen de le faire plutôt pour une fonction quelconque de type void?
Je ne saisis pas bien. Vous avez certaines latitudes sur la concordance

des types.
Ici, nous avions simplement déclaré dans la structure un int (*fn)()
qui a permis d'affecter des int (*fn)(int), comme ça aurait pu être
autre chose (avec les précautions qui s'imposent). int (*fn)(void)
aurait été bien plus restrictif. Mais le type de retour doit être
spécifié. Éventuellement à void.

--
Pierre Maurette



Avatar
Nicolas Cherel
Pierre Maurette wrote:

Bonjour,

y-a-t'il moyen en C, d'insérer une ou des fonctions dans une structure
de données?

typedef struct Complex Complex;
struct Complex {
int value;
int (*fn)();
char *mesg;
};


Oui, c'est possible, c'est même facile. Vous aviez bien commencé. Ce qui
reste à faire, c'est initiliser et utiliser les membres fn de vos
structures.
Le plus simple pour initialiser C.fn, c'est de lui affecter l'adresse
d'une fonction fonct. On peut pour cela utiliser indifféremment fonct ou
&fonct. Cette facilité - que je trouve regrettable, mais c'est un troll
- n'est pas unique dans le langage.
Un code de test pourrait être (OK, le style est à chier):

int carre(int i) {return i * i;}
int cube(int i) {return i * i * i;}

enum {ONE = 10, TWO};

Complex table[] = {
ONE, &cube, "premier message",
TWO, &carre, "deuxième message",
};

printf("%dt%dt%sn", table[0].value, table[0].fn(table[0].value),
table[0].mesg);
printf("%dt%dt%sn", table[1].value, table[1].fn(table[1].value),
table[1].mesg);

Comme plusieurs fois signalé, soyez prudent avec les nommages. double
doit être proscrit, et je n'aime pas trop Complex dans ce contexte.



En passant, pour les pointeurs de fonction : quelle est la différence
entre "&fonction" et "fonction" ?. Un pointeur sur fonction peut être
alloué avec l'un ou l'autre, sans influence sur le résultat.
Si vous pouvez m'éclairer ...


Avatar
Pierre Maurette
Pierre Maurette wrote:
[...]

int carre(int i) {return i * i;}
int cube(int i) {return i * i * i;}

enum {ONE = 10, TWO};

Complex table[] = {
ONE, &cube, "premier message",
TWO, &carre, "deuxième message",
};
[...]


En passant, pour les pointeurs de fonction : quelle est la différence entre
"&fonction" et "fonction" ?. Un pointeur sur fonction peut être alloué avec
l'un ou l'autre, sans influence sur le résultat.
Si vous pouvez m'éclairer ...
Si "fonction" le nom d'une fonction - 'function designator' - , c'est

équivalent effectivement. Néanmoins, il y a un pied jacon, et mon code
n'est peut-être pas "bon" (bien que techniquement correct).

cube, comme printf, est de type 'fonction retournant un int'. Dans tous
les cas sauf avec les opérateurs sizeof et &, il est converti vers le
type 'pointeur vers fonction retournant un int'. L'opérateur & fait son
boulot normal. Pour faire simple et en négligeant sizeof, cube, ou
printf, et &cube, ou &printf, sont toujours remplacés par &cube ou
&printf.

Maintenant, imaginons que je modifie mon code, parce que je viens de me
rendre compte que j'ai un
int cucube(int);
en bibliothèque. Econome, je vais jeter ma fonction cube() et faire:
int (*cube)() = cucube;
Et crack !
cube est de type 'pointeur vers fonction retournant un int', et non pas
'fonction retournant un int'. Donc, &cube est de type 'pointeur vers
pointeur vers fonction retournant un int', en fait c'est simplement et
logiquement l'adresse de ma variable cube, donc boum. Enfin, il y aura
au moins un warning, quand même.
Je n'aurais pas eu de problème si j'avais codé:
Complex table[] = {
ONE, cube, "premier message",
TWO, carre, "deuxième message",
};


Code pour faire mumuse par les jours pluvieux que nous vivons:

int cube(char i) {return i * i * i;}

typedef int(*TFonctRetourneInt)();
TFonctRetourneInt fn1 = NULL, fn2 = NULL, fn3 = NULL, fn4 = NULL;

fn1 = printf;
fn2 = &printf;
fn3 = fn2;
fn4 = &fn2;/* caca, warning */

fn1("%pt%pt%pn", cube, &cube, *cube);
fn2("%pt%pt%pn", printf, &printf, *printf);
(*fn1)("%pt%pt%pn", fn2, &fn2, *fn2);
printf("%pt%pt%pn", fn3, &fn3, *fn3);
(*printf)("%pt%pt%pn", fn4, &fn4, *fn4);

/* printf("%lun", sizeof cube); */
printf("%lun", sizeof &cube);

--
Pierre Maurette


Avatar
Pierre Maurette
(supersedes )

Pierre Maurette wrote:
[...]

int carre(int i) {return i * i;}
int cube(int i) {return i * i * i;}

enum {ONE = 10, TWO};

Complex table[] = {
ONE, &cube, "premier message",
TWO, &carre, "deuxième message",
};
[...]


En passant, pour les pointeurs de fonction : quelle est la différence entre
"&fonction" et "fonction" ?. Un pointeur sur fonction peut être alloué avec
l'un ou l'autre, sans influence sur le résultat.
Si vous pouvez m'éclairer ...
Si "fonction" est le nom d'une fonction - 'function designator' - ,

c'est équivalent effectivement. Néanmoins, il y a un pied jacon, et mon
code n'est peut-être pas "bon", bien que techniquement correct.

cube, comme printf, est de type 'fonction retournant un int'. Dans tous
les cas sauf avec les opérateurs sizeof et &, il est converti vers le
type 'pointeur vers fonction retournant un int'. L'opérateur & fait son
boulot normal. Pour faire simple et en négligeant sizeof, cube, ou
printf, et &cube, ou &printf, sont toujours remplacés par &cube ou
&printf.

Maintenant, imaginons que je modifie mon code, parce que je viens de me
rendre compte que j'ai un
int cucube(int);
en bibliothèque. Économe, je vais jeter ma fonction cube() et faire:
int (*cube)() = cucube;
Et crack !
cube est de type 'pointeur vers fonction retournant un int', et non pas
'fonction retournant un int'. Donc, &cube est de type 'pointeur vers
pointeur vers fonction retournant un int', en fait c'est simplement et
logiquement l'adresse de ma variable cube, donc boum. Enfin, il y aura
au moins un warning, quand même.
Je n'aurais pas eu de problème si j'avais codé:
Complex table[] = {
ONE, cube, "premier message",
TWO, carre, "deuxième message",
};


Code pour faire mumuse par les jours pluvieux que nous vivons:

int cube(char i) {return i * i * i;}

typedef int(*TFonctRetourneInt)();
TFonctRetourneInt fn1 = NULL, fn2 = NULL, fn3 = NULL, fn4 = NULL;

fn1 = printf;
fn2 = &printf;
fn3 = fn2;
fn4 = &fn2;/* caca, warning */

fn1("%pt%pt%pn", cube, &cube, *cube);
fn2("%pt%pt%pn", printf, &printf, *printf);
(*fn1)("%pt%pt%pn", fn2, &fn2, *fn2);
printf("%pt%pt%pn", fn3, &fn3, *fn3);
(*printf)("%pt%pt%pn", fn4, &fn4, *fn4);

/* printf("%lun", sizeof cube); */
printf("%lun", sizeof &cube);


--
Pierre Maurette


Avatar
Antoine Leca
Nicolas Cherel wrote:

En passant, pour les pointeurs de fonction : quelle est la différence
entre "&fonction" et "fonction" ?


À l'utilisation, je crois qu'il n'y en a pas tant qu'il n'y a pas de macros
"fonction".

Techniquement (et toujours sans macros en vue), le premier est un pointeur
vers une fonction et le second est un désignateur de fonction : ce sont donc
deux entités différentes du point de vue de la grammaire. Mais l'on peut
utiliser l'un à la place de l'autre (et ce même sur les très vieux
compilateurs, pour autant que je me souvienne), sauf dans des constructions
tordues (par exemple comme arguments de & ou de sizeof, où seule la seconde
forme sera autorisée).


Antoine

1 2 3