Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une
variable globale.
Je pose la question car K.N. King évoque cette possibilité dans son
manuel de C et je voudrais savoir si ça a un quelconque intérêt et si ça
correspond à une pratique réelle.
[Je ne vois pas trop l'intérêt puisque si on définit une fonction en
classe statique c'est pour limiter son accès depuis un fichier externe à
sa définition et donc c'est circonvenir cette limitation d'accès que
d'utiliser un pointeur vers cette fonction.]
Si ma question n'est pas claire, je placerai ici l'extrait du livre de King.
[Je ne vois pas trop l'intérêt puisque si on définit une fonction en classe statique c'est pour limiter son accès depuis un fichier externe à sa définition et donc c'est circonvenir cette limitation d'accès que d'utiliser un pointeur vers cette fonction.]
Je vois bien un intérêt : réduire la maintenabilité de l'application :-D
Plus sérieusement, on peut imaginer utiliser cette propriété pour « émuler » le système de classes de C++ dans C. C'est à dire que les fonction static sont effectivement protégées, mais pour qu'on puisse faire un héritage du module, il faut pouvoir accéder à ces « méthodes » protégées. On peut aussi imaginer utiliser cette propriété pour créer des plugins, chargés dynamiquements, dont les fonctions ne sont accessibles depuis l'extérieur que via des pointeurs contenus dans une structures. Ça pourrait assurer le contournement des conflits de fonctions ayant le même prototype (mais là je demandes confirmation).
Je suis sûr que ton imagination t'aidera comme elle vient de m'aider ;) -- Mickaël Wolff aka Lupus Michaelis http://lupusmic.org
candide a écrit :
Bonjour,
Bonjour,
[Je ne vois pas trop l'intérêt puisque si on définit une fonction en
classe statique c'est pour limiter son accès depuis un fichier externe à
sa définition et donc c'est circonvenir cette limitation d'accès que
d'utiliser un pointeur vers cette fonction.]
Je vois bien un intérêt : réduire la maintenabilité de l'application :-D
Plus sérieusement, on peut imaginer utiliser cette propriété pour «
émuler » le système de classes de C++ dans C. C'est à dire que les
fonction static sont effectivement protégées, mais pour qu'on puisse
faire un héritage du module, il faut pouvoir accéder à ces « méthodes »
protégées.
On peut aussi imaginer utiliser cette propriété pour créer des
plugins, chargés dynamiquements, dont les fonctions ne sont accessibles
depuis l'extérieur que via des pointeurs contenus dans une structures.
Ça pourrait assurer le contournement des conflits de fonctions ayant le
même prototype (mais là je demandes confirmation).
Je suis sûr que ton imagination t'aidera comme elle vient de m'aider ;)
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
[Je ne vois pas trop l'intérêt puisque si on définit une fonction en classe statique c'est pour limiter son accès depuis un fichier externe à sa définition et donc c'est circonvenir cette limitation d'accès que d'utiliser un pointeur vers cette fonction.]
Je vois bien un intérêt : réduire la maintenabilité de l'application :-D
Plus sérieusement, on peut imaginer utiliser cette propriété pour « émuler » le système de classes de C++ dans C. C'est à dire que les fonction static sont effectivement protégées, mais pour qu'on puisse faire un héritage du module, il faut pouvoir accéder à ces « méthodes » protégées. On peut aussi imaginer utiliser cette propriété pour créer des plugins, chargés dynamiquements, dont les fonctions ne sont accessibles depuis l'extérieur que via des pointeurs contenus dans une structures. Ça pourrait assurer le contournement des conflits de fonctions ayant le même prototype (mais là je demandes confirmation).
Je suis sûr que ton imagination t'aidera comme elle vient de m'aider ;) -- Mickaël Wolff aka Lupus Michaelis http://lupusmic.org
Erwan David
candide écrivait :
Bonjour,
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une variable globale.
Je pose la question car K.N. King évoque cette possibilité dans son manuel de C et je voudrais savoir si ça a un quelconque intérêt et si ça correspond à une pratique réelle.
J'ai déjà vu faire, pour un file system embarqué sur flash : à l'initialisation on rmepli une structure avec des adresses de fonctions statiques de bas niveau pour la flash (écrire, lire effacer un bloc) et la lib de file system appelle les fonctions via les champs de cette structure.
-- Le travail n'est pas une bonne chose. Si ça l'était, les riches l'auraient accaparé
candide <candide@free.invalid> écrivait :
Bonjour,
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une
variable globale.
Je pose la question car K.N. King évoque cette possibilité dans son
manuel de C et je voudrais savoir si ça a un quelconque intérêt et si
ça correspond à une pratique réelle.
J'ai déjà vu faire, pour un file system embarqué sur flash :
à l'initialisation on rmepli une structure avec des adresses de
fonctions statiques de bas niveau pour la flash (écrire, lire effacer un bloc)
et la lib de file system appelle les fonctions via les champs de cette
structure.
--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une variable globale.
Je pose la question car K.N. King évoque cette possibilité dans son manuel de C et je voudrais savoir si ça a un quelconque intérêt et si ça correspond à une pratique réelle.
J'ai déjà vu faire, pour un file system embarqué sur flash : à l'initialisation on rmepli une structure avec des adresses de fonctions statiques de bas niveau pour la flash (écrire, lire effacer un bloc) et la lib de file system appelle les fonctions via les champs de cette structure.
-- Le travail n'est pas une bonne chose. Si ça l'était, les riches l'auraient accaparé
espie
In article <488f4a6e$0$7251$, candide wrote:
Bonjour,
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une variable globale.
Facile: en utilisant autre chose de global.
Par exemple, une fonction non-statique.
Je te laisse mediter sur la chose suivante: un fichier C qui ne contient QUE des definitions d'objets statiques n'a pas grande utilite. tu es oblige de communiquer avec le reste du monde par des trucs globaux, que ce soit des fonctions ou des variables.
Une bonne part du design des gros projets, c'est precisement de limiter les interactions entre les diverses composants a un petit nombre d'interfaces judicieusement definies.
Tu peux par exemple avoir une fonction globale qui te remplit une structure (pointeur passe en parametre) avec les pointeurs sur les fonctions statiques dont nous parlons.
Ca marche tres bien, ca ne reduit absolument pas la maintenabilite de l'application, bien au contraire... Ca permet de n'exposer qu'un seul nom public, et d'avoir les autres noms de fonctions locales au fichier C, donc t'as meme pas besoin d'avoir de conventions de nommage pour eviter les collisions avec le reste du monde.
In article <488f4a6e$0$7251$426a74cc@news.free.fr>,
candide <candide@free.invalid> wrote:
Bonjour,
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une
variable globale.
Facile: en utilisant autre chose de global.
Par exemple, une fonction non-statique.
Je te laisse mediter sur la chose suivante:
un fichier C qui ne contient QUE des definitions d'objets statiques n'a
pas grande utilite. tu es oblige de communiquer avec le reste du monde
par des trucs globaux, que ce soit des fonctions ou des variables.
Une bonne part du design des gros projets, c'est precisement de limiter
les interactions entre les diverses composants a un petit nombre
d'interfaces judicieusement definies.
Tu peux par exemple avoir une fonction globale qui te remplit une structure
(pointeur passe en parametre) avec les pointeurs sur les fonctions
statiques dont nous parlons.
Ca marche tres bien, ca ne reduit absolument pas la maintenabilite de
l'application, bien au contraire... Ca permet de n'exposer qu'un seul
nom public, et d'avoir les autres noms de fonctions locales au fichier C,
donc t'as meme pas besoin d'avoir de conventions de nommage pour eviter
les collisions avec le reste du monde.
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une variable globale.
Facile: en utilisant autre chose de global.
Par exemple, une fonction non-statique.
Je te laisse mediter sur la chose suivante: un fichier C qui ne contient QUE des definitions d'objets statiques n'a pas grande utilite. tu es oblige de communiquer avec le reste du monde par des trucs globaux, que ce soit des fonctions ou des variables.
Une bonne part du design des gros projets, c'est precisement de limiter les interactions entre les diverses composants a un petit nombre d'interfaces judicieusement definies.
Tu peux par exemple avoir une fonction globale qui te remplit une structure (pointeur passe en parametre) avec les pointeurs sur les fonctions statiques dont nous parlons.
Ca marche tres bien, ca ne reduit absolument pas la maintenabilite de l'application, bien au contraire... Ca permet de n'exposer qu'un seul nom public, et d'avoir les autres noms de fonctions locales au fichier C, donc t'as meme pas besoin d'avoir de conventions de nommage pour eviter les collisions avec le reste du monde.
Thierry B.
--{ candide a plopé ceci: }--
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me parait un peu tordu... Il faudrait que le code de a.c appelle une fonction du fichier b.c pour obtenir l'adresse de f...
-- # find / -type f -uid 0 -perm -u=sx -exec chmod u-s {} ; Après ça plein de choses vont très très mal marcher... Mais comme ton système a déjà de gros problèmes entre son clavier et sa chaise, ce n'est pas trop grave. --{ YBM, répondant à Ptilou dans fcol.configuration }--
--{ candide a plopé ceci: }--
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me
parait un peu tordu... Il faudrait que le code de a.c appelle
une fonction du fichier b.c pour obtenir l'adresse de f...
--
# find / -type f -uid 0 -perm -u=sx -exec chmod u-s {} ;
Après ça plein de choses vont très très mal marcher... Mais comme ton système
a déjà de gros problèmes entre son clavier et sa chaise, ce n'est pas trop
grave. --{ YBM, répondant à Ptilou dans fcol.configuration }--
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me parait un peu tordu... Il faudrait que le code de a.c appelle une fonction du fichier b.c pour obtenir l'adresse de f...
-- # find / -type f -uid 0 -perm -u=sx -exec chmod u-s {} ; Après ça plein de choses vont très très mal marcher... Mais comme ton système a déjà de gros problèmes entre son clavier et sa chaise, ce n'est pas trop grave. --{ YBM, répondant à Ptilou dans fcol.configuration }--
Thierry B.
--{ Thierry B. a plopé ceci: }--
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me parait un peu tordu... Il faudrait que le code de a.c appelle une fonction du fichier b.c pour obtenir l'adresse de f...
C'est bon, j'ai lu l'exemple donné par Marc Espie, et en fait ça me donne quelques idées... Merci d'avoir lancé ce fil :)
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me
parait un peu tordu... Il faudrait que le code de a.c appelle
une fonction du fichier b.c pour obtenir l'adresse de f...
C'est bon, j'ai lu l'exemple donné par Marc Espie, et en fait
ça me donne quelques idées... Merci d'avoir lancé ce fil :)
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me parait un peu tordu... Il faudrait que le code de a.c appelle une fonction du fichier b.c pour obtenir l'adresse de f...
C'est bon, j'ai lu l'exemple donné par Marc Espie, et en fait ça me donne quelques idées... Merci d'avoir lancé ce fil :)
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une variable globale.
Facile: en utilisant autre chose de global.
Par exemple, une fonction non-statique.
Je te laisse mediter sur la chose suivante: un fichier C qui ne contient QUE des definitions d'objets statiques n'a pas grande utilite. tu es oblige de communiquer avec le reste du monde par des trucs globaux, que ce soit des fonctions ou des variables.
Une bonne part du design des gros projets, c'est precisement de limiter les interactions entre les diverses composants a un petit nombre d'interfaces judicieusement definies.
Tu peux par exemple avoir une fonction globale qui te remplit une structure (pointeur passe en parametre) avec les pointeurs sur les fonctions statiques dont nous parlons.
Ca marche tres bien, ca ne reduit absolument pas la maintenabilite de l'application, bien au contraire... Ca permet de n'exposer qu'un seul nom public, et d'avoir les autres noms de fonctions locales au fichier C, donc t'as meme pas besoin d'avoir de conventions de nommage pour eviter les collisions avec le reste du monde.
C'est même tout à fait comme ça qu'il faut faire pour respecter l'encapsulation et donc augmenter la maintenabilité. En plus, c'est une sorte de "programmation objet" en C.
Merci à toi, Marc, qui a très bien expliqué la construction.
Marc Espie a écrit :
In article <488f4a6e$0$7251$426a74cc@news.free.fr>,
candide <candide@free.invalid> wrote:
Bonjour,
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une
variable globale.
Facile: en utilisant autre chose de global.
Par exemple, une fonction non-statique.
Je te laisse mediter sur la chose suivante:
un fichier C qui ne contient QUE des definitions d'objets statiques n'a
pas grande utilite. tu es oblige de communiquer avec le reste du monde
par des trucs globaux, que ce soit des fonctions ou des variables.
Une bonne part du design des gros projets, c'est precisement de limiter
les interactions entre les diverses composants a un petit nombre
d'interfaces judicieusement definies.
Tu peux par exemple avoir une fonction globale qui te remplit une structure
(pointeur passe en parametre) avec les pointeurs sur les fonctions
statiques dont nous parlons.
Ca marche tres bien, ca ne reduit absolument pas la maintenabilite de
l'application, bien au contraire... Ca permet de n'exposer qu'un seul
nom public, et d'avoir les autres noms de fonctions locales au fichier C,
donc t'as meme pas besoin d'avoir de conventions de nommage pour eviter
les collisions avec le reste du monde.
C'est même tout à fait comme ça qu'il faut faire pour respecter
l'encapsulation et donc augmenter la maintenabilité.
En plus, c'est une sorte de "programmation objet" en C.
Merci à toi, Marc, qui a très bien expliqué la construction.
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
En plus je vois pas comment c'est possible à moins d'utiliser une variable globale.
Facile: en utilisant autre chose de global.
Par exemple, une fonction non-statique.
Je te laisse mediter sur la chose suivante: un fichier C qui ne contient QUE des definitions d'objets statiques n'a pas grande utilite. tu es oblige de communiquer avec le reste du monde par des trucs globaux, que ce soit des fonctions ou des variables.
Une bonne part du design des gros projets, c'est precisement de limiter les interactions entre les diverses composants a un petit nombre d'interfaces judicieusement definies.
Tu peux par exemple avoir une fonction globale qui te remplit une structure (pointeur passe en parametre) avec les pointeurs sur les fonctions statiques dont nous parlons.
Ca marche tres bien, ca ne reduit absolument pas la maintenabilite de l'application, bien au contraire... Ca permet de n'exposer qu'un seul nom public, et d'avoir les autres noms de fonctions locales au fichier C, donc t'as meme pas besoin d'avoir de conventions de nommage pour eviter les collisions avec le reste du monde.
C'est même tout à fait comme ça qu'il faut faire pour respecter l'encapsulation et donc augmenter la maintenabilité. En plus, c'est une sorte de "programmation objet" en C.
Merci à toi, Marc, qui a très bien expliqué la construction.
Côme Desplats
Thierry B. wrote:
--{ Thierry B. a plopé ceci: }--
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me parait un peu tordu... Il faudrait que le code de a.c appelle une fonction du fichier b.c pour obtenir l'adresse de f...
C'est bon, j'ai lu l'exemple donné par Marc Espie, et en fait ça me donne quelques idées... Merci d'avoir lancé ce fil :)
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me
parait un peu tordu... Il faudrait que le code de a.c appelle
une fonction du fichier b.c pour obtenir l'adresse de f...
C'est bon, j'ai lu l'exemple donné par Marc Espie, et en fait
ça me donne quelques idées... Merci d'avoir lancé ce fil :)
Voici une doc qui peut aussi donner quelques idées d'implémentation :
http://chgi.developpez.com/c/objet/
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Pourrais-tu proposer un exemple minimum, svp ? Parce que ça me parait un peu tordu... Il faudrait que le code de a.c appelle une fonction du fichier b.c pour obtenir l'adresse de f...
C'est bon, j'ai lu l'exemple donné par Marc Espie, et en fait ça me donne quelques idées... Merci d'avoir lancé ce fil :)
Effectivement, la variable globale que je suggérais d'utiliser n'est pas nécessaire.
J'ai trouvé assez peu de doc sur la question mais dans celle que j'ai trouvée, l'idée de la structure contenant les adresses des fonctions static et qu'on initialise revient le plus souvent.
Effectivement, la variable globale que je suggérais d'utiliser n'est pas
nécessaire.
J'ai trouvé assez peu de doc sur la question mais dans celle que j'ai
trouvée, l'idée de la structure contenant les adresses des fonctions
static et qu'on initialise revient le plus souvent.
Effectivement, la variable globale que je suggérais d'utiliser n'est pas nécessaire.
J'ai trouvé assez peu de doc sur la question mais dans celle que j'ai trouvée, l'idée de la structure contenant les adresses des fonctions static et qu'on initialise revient le plus souvent.
[...] J'ai trouvé assez peu de doc sur la question mais dans celle que j'ai trouvée, l'idée de la structure contenant les adresses des fonctions static et qu'on initialise revient le plus souvent. [...]
[...]
J'ai trouvé assez peu de doc sur la question mais dans celle que j'ai
trouvée, l'idée de la structure contenant les adresses des fonctions
static et qu'on initialise revient le plus souvent.
[...]
Pour un exemple industriel, c'est le modèle qu'utilise l'interface
PKCS#11 v2 :
http://www.rsa.com/rsalabs/node.asp?id!33
[...] J'ai trouvé assez peu de doc sur la question mais dans celle que j'ai trouvée, l'idée de la structure contenant les adresses des fonctions static et qu'on initialise revient le plus souvent. [...]
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Oui, mais tu n'utiliseras pas le symbole de la fonction f dans le fichier a.c . En gros, tu peux trouver g(f) dans b.c mais pas dans a.c .
[...] Je pose la question car K.N. King évoque cette possibilité dans son manuel de C et je voudrais savoir si ça a un quelconque intérêt et si ça correspond à une pratique réelle. [Je ne vois pas trop l'intérêt puisque si on définit une fonction en classe statique c'est pour limiter son accès depuis un fichier externe à sa définition et donc c'est circonvenir cette limitation d'accès que d'utiliser un pointeur vers cette fonction.]
Ça permet de faire une librairie partagée qui définit des prototypes de base pour des fonctions à appeler. L'important c'est d'avoir le prototype pour éviter d'exploser la pile d'appels, et de définir le comportement attendu de la fonction dans un header.
L'intérêt c'est le même que pour une fonction static "non appellée par pointeur" : moins de symboles, moins de risques de conflits de noms, code plus simple à appréhender.
Par exemple, tu peux implémenter un algorithme de tri qui prend en premier paramètre une fonction de comparaison qui elle même prend deux paramètres. L'utilisateur de la librairie n'aura pas à se soucier de l'algorithme, mais seulement de la comparaison, ça rejoint le concept "interface" de la POO.
Par exemple, tu peux faire: typedef int (*fonction_de_comparaison)(void*,void*); et ta tri_par_bulle prendra alors une liste d'élèments et la fonction_de_comparaison. De la même manière qu'il faut établir une convention pour la fonction de comparaison (par exemple le set 2 1 3 5 avec la fonction "supérieur" donne 1 2 3 5 et non pas 5 3 2 1), il faut établir une convention sur la représentation de la liste d'élèments à trier (un tableau de pointeurs par exemple), et sur celle une fois triée.
Pour l'utilisation ? outre faire de l'objet en C, c'est utilisé partout dès que tu as des appels à des entrées/sorties asynchrones, la Glib utilise ça lors des "g_io_add_watch", POSIX lorsque tu rajoute un "handler" via la fonction signal etc.
L'avantage: ça permet de s'abstraire de beaucoup de choses et de faire du code très modulaire. L'inconvénient: c'est très probable qu'un utilisateur se trompe de types à un moment ou à un autre car avec mon exemple précédent, la commande suivante passera inaperçue à la compilation: trier_par_bulle( &compare_torchons, (void*) liste_serviettes ) même si on est incapable de trier une liste de serviettes avec une fonction sur les torchons. Au mieux t'as une segfault, au pire t'as un résultat faux dans certains cas vicieux qui n'arrivent qu'en production (typiquement veux comparer des entiers signés, passe un non signé et tu testes que sur des cas "qui marchent").
Merci
De rien ;) j'espère avoir été utile.
--Lucas
candide wrote:
Bonjour,
Bonjour,
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une
fonction g qui prend en argument l'adresse d'une fonction f définie
static dans un autre fichier b.c ?
Oui, mais tu n'utiliseras pas le symbole de la fonction f dans le
fichier a.c .
En gros, tu peux trouver g(f) dans b.c mais pas dans a.c .
[...]
Je pose la question car K.N. King évoque cette possibilité dans son
manuel de C et je voudrais savoir si ça a un quelconque intérêt et si ça
correspond à une pratique réelle.
[Je ne vois pas trop l'intérêt puisque si on définit une fonction en
classe statique c'est pour limiter son accès depuis un fichier externe à
sa définition et donc c'est circonvenir cette limitation d'accès que
d'utiliser un pointeur vers cette fonction.]
Ça permet de faire une librairie partagée qui définit des prototypes de
base pour des fonctions à appeler. L'important c'est d'avoir le
prototype pour éviter d'exploser la pile d'appels, et de définir le
comportement attendu de la fonction dans un header.
L'intérêt c'est le même que pour une fonction static "non appellée par
pointeur" : moins de symboles, moins de risques de conflits de noms,
code plus simple à appréhender.
Par exemple, tu peux implémenter un algorithme de tri qui prend en
premier paramètre une fonction de comparaison qui elle même prend deux
paramètres. L'utilisateur de la librairie n'aura pas à se soucier de
l'algorithme, mais seulement de la comparaison, ça rejoint le concept
"interface" de la POO.
Par exemple, tu peux faire:
typedef int (*fonction_de_comparaison)(void*,void*);
et ta tri_par_bulle prendra alors une liste d'élèments et la
fonction_de_comparaison. De la même manière qu'il faut établir une
convention pour la fonction de comparaison (par exemple le set 2 1 3 5
avec la fonction "supérieur" donne 1 2 3 5 et non pas 5 3 2 1), il faut
établir une convention sur la représentation de la liste d'élèments à
trier (un tableau de pointeurs par exemple), et sur celle une fois triée.
Pour l'utilisation ? outre faire de l'objet en C, c'est utilisé partout
dès que tu as des appels à des entrées/sorties asynchrones, la Glib
utilise ça lors des "g_io_add_watch", POSIX lorsque tu rajoute un
"handler" via la fonction signal etc.
L'avantage: ça permet de s'abstraire de beaucoup de choses et de faire
du code très modulaire. L'inconvénient: c'est très probable qu'un
utilisateur se trompe de types à un moment ou à un autre car avec mon
exemple précédent, la commande suivante passera inaperçue à la compilation:
trier_par_bulle( &compare_torchons, (void*) liste_serviettes )
même si on est incapable de trier une liste de serviettes avec une
fonction sur les torchons.
Au mieux t'as une segfault, au pire t'as un résultat faux dans certains
cas vicieux qui n'arrivent qu'en production (typiquement veux comparer
des entiers signés, passe un non signé et tu testes que sur des cas "qui
marchent").
Avez-vous déjà rencontré du code qui appelle depuis un fichier a.c une fonction g qui prend en argument l'adresse d'une fonction f définie static dans un autre fichier b.c ?
Oui, mais tu n'utiliseras pas le symbole de la fonction f dans le fichier a.c . En gros, tu peux trouver g(f) dans b.c mais pas dans a.c .
[...] Je pose la question car K.N. King évoque cette possibilité dans son manuel de C et je voudrais savoir si ça a un quelconque intérêt et si ça correspond à une pratique réelle. [Je ne vois pas trop l'intérêt puisque si on définit une fonction en classe statique c'est pour limiter son accès depuis un fichier externe à sa définition et donc c'est circonvenir cette limitation d'accès que d'utiliser un pointeur vers cette fonction.]
Ça permet de faire une librairie partagée qui définit des prototypes de base pour des fonctions à appeler. L'important c'est d'avoir le prototype pour éviter d'exploser la pile d'appels, et de définir le comportement attendu de la fonction dans un header.
L'intérêt c'est le même que pour une fonction static "non appellée par pointeur" : moins de symboles, moins de risques de conflits de noms, code plus simple à appréhender.
Par exemple, tu peux implémenter un algorithme de tri qui prend en premier paramètre une fonction de comparaison qui elle même prend deux paramètres. L'utilisateur de la librairie n'aura pas à se soucier de l'algorithme, mais seulement de la comparaison, ça rejoint le concept "interface" de la POO.
Par exemple, tu peux faire: typedef int (*fonction_de_comparaison)(void*,void*); et ta tri_par_bulle prendra alors une liste d'élèments et la fonction_de_comparaison. De la même manière qu'il faut établir une convention pour la fonction de comparaison (par exemple le set 2 1 3 5 avec la fonction "supérieur" donne 1 2 3 5 et non pas 5 3 2 1), il faut établir une convention sur la représentation de la liste d'élèments à trier (un tableau de pointeurs par exemple), et sur celle une fois triée.
Pour l'utilisation ? outre faire de l'objet en C, c'est utilisé partout dès que tu as des appels à des entrées/sorties asynchrones, la Glib utilise ça lors des "g_io_add_watch", POSIX lorsque tu rajoute un "handler" via la fonction signal etc.
L'avantage: ça permet de s'abstraire de beaucoup de choses et de faire du code très modulaire. L'inconvénient: c'est très probable qu'un utilisateur se trompe de types à un moment ou à un autre car avec mon exemple précédent, la commande suivante passera inaperçue à la compilation: trier_par_bulle( &compare_torchons, (void*) liste_serviettes ) même si on est incapable de trier une liste de serviettes avec une fonction sur les torchons. Au mieux t'as une segfault, au pire t'as un résultat faux dans certains cas vicieux qui n'arrivent qu'en production (typiquement veux comparer des entiers signés, passe un non signé et tu testes que sur des cas "qui marchent").