OVH Cloud OVH Cloud

Pointeurs vers fonctions

54 réponses
Avatar
Pierre Maurette
Bonjour,
Mon problème est peut-être plus C que C++, mais je le fais facilement
apparaître avec new[], et de plus c'est la réponse de la norme C++ qui
m'intéresse le plus.
Si on définit une variable pointeur de fonction :
int(*pF)(double, double) = NULL;
on a la facilité d'utiliser ou non, indifféremment, les opérateurrs * et & ,
ou plus exactement on a exceptionnellement la possibilité de les omettre :
int fonct(double x, double y) {return (int)(x * y);}
...
pF = &fonct;
pF = fonct;
...
x = pF(4.0, 2.0);
x = (*pF)(4.0, 2.0);

Question : qu'en dit la norme ? (pas pu trouver)

Si je désire un tableau de fonctions dont la taile sera déterminée à
l'exécution, je dois faire :
int(**pF)(double, double) = NULL;
Ensuite, en C comme en C++ :
int n = 12;
pF = (int(**)(double, double))malloc(n * sizeof(int(*)(double, double)));
x = pF[4](4.0, 2.0);
Pas beau, puisque pF n'a pas le même type dans les deux lignes, mais logique
au vu de ce qui précède.
Passons au new[] :
pF = new (int(*)(double, double))[n];
La famille du Gnou accepte, et le résultat est celui attendu. Chez Borland,
c'est non., conversion de type impossible
Les Gnou interprètent pF en fonction de l'appel de malloc() ou de new[], pas
Borland. Je ne suis pas contre, je préfèrerais même que ne soient pas
autorisées les facilités initiales, donc que le typedef s'impose de
lui-même.
Question : Qu'en dit la norme ? Qui a raison ?

Bien entendu, un typedef s'impose, et tout rentre dans l'ordre.

typedef int(*Fonc_Type)(double, double);
Fonc_Type* pF1;
Fonc_Type* pF2;
int n = 12;
pF1 = (Fonc_Type*) malloc(n * sizeof(Fonc_Type));
pF2 = new Fonc_Type[n];
pF1[5] = f1;
pF2[6] = f2;

Merci pour vous lulières,
Pierre

10 réponses

1 2 3 4 5
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
"Michel Michaud" writes:

| (dans le cas de void, c'était nouveau d'où l'invention, dans
| l'autre, il faudrait trouver le « rationale », il me semble qu'il
| existe pour ISO C, à moi que tu connaisses la raison de cette
| invention ?)

« void » est une invention de BS (surtout pour C with Classes) et
quand il a fait la proposition au comité ANSI, il a bine pris garde de
ne pas inclure le trou void* -> T*. Cependant, le comité ANSI n'a pas
resisté devant l'invention.


La rationnale ne donne aucune raison pour cette conversion. J'imagine
que c'était la désire de ne pas exiger une conversion explicite de la
valeur de retour de malloc, mais ce n'est que de la spéculation de ma
part.

Il faut dire que beaucoup de compilateurs pré-norme permettaient des
conversions implicites dans tous les sens. J'ai déjà vu pas mal de
programmes C sans la moindre déclaration de malloc (et donc, avec une
déclaration implicite qu'il renvoie un int), par exemple. Ça n'a jamais
été légal, mais ça marchait avec beaucoup de compilateurs, et c'était
malheureusement assez courant. Pour beaucoup d'auteurs de C à l'époque,
il n'y avait que des VAX.

En ce qui concerne l'omision de « * » -- qui n'est pas valide en C K+R
-- le comité ANSI a probablement aussi inventé une raison pour cette
invention ; mais je ne saurais te dire exactement quoi à part supiter
« certains programmeurs C trouvent cela plus simple à écrire ».


D'après la rationnale (http://www.lysator.liu.se/c/rat/title.html) :

Pointers to functions may be used either as (*pf)() or as pf(). The
latter construct, not sanctioned in the Base Document, appears in
some present versions of C, is unambiguous, invalidates no old code,
and can be an important shorthand. The shorthand is useful for
packages that present only one external name, which designates a
structure full of pointers to objects and functions: member
functions can be called as graphics.open(file) instead of
(*graphics.open)(file).

The treatment of function designators can lead to some curious, but
valid, syntactic forms. Given the declarations:

int f(), (*pf)();

then all of the following expressions are valid function calls:

(&f)(); f(); (*f)(); (**f)(); (***f)();
pf(); (*pf)(); (**pf)(); (***pf)();

The first expression on each line was discussed in the previous
paragraph. The second is conventional usage. All subsequent
expressions take advantage of the implicit conversion of a function
designator to a pointer value, in nearly all expression contexts.
The Committee saw no real harm in allowing these forms; outlawing
forms like (*f)(), while still permitting *a (for int a[]), simply
seemed more trouble than it was worth.

On remarque que même pour le comité C, la forme usuelle (ou
« conventionnelle »), c'est (*pf)().

En ce qui concerne la motivation de base, je suis prèsque sûr que
l'extention était assez répandue -- je m'en souviens de son existance
bien avant C90, et j'avoue avoir été étonné quand Gaby a dit qu'elle
n'était pas dans K&R 1.

| >> En fait, tiens, est-ce qu'il y a un problème réel à permettre
| >> l'autre syntaxe, ou est-ce qu'on veut simplement choisir pour le
| >> programmeur comment il peut faire les choses ?

| > je ne sais pas. Je n'ai jamais poussé la réflexion au delà de la
| > simple curiosité du d« tiens, ce n'est pas permis ».

| La règle K&R originale est bien intéressante historiquement, mais
| ANSI/ISO C existait bien avant ISO C++.

oui mais, je ne crois pas que cette invention était quelque chose qui
ait fait unanimité dans la communauté C++ -- surtout chez ceux qui
sont attachés à la notion de type.


Je ne crois pas qu'elle ait fait l'unanimité dans la communauté C non
plus. Le problème, c'est que c'était une pratique existante avec
certains compilateurs.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
"Pierre Maurette" <mmaauurreettttttee.ppiieerrrree@@ffrreeee.ffrr>
writes:

| "Gabriel Dos Reis" a écrit dans le
| message de news:

| > writes:

| > | Ce n'est pas une raison. J'ai écrit de l'assembleur pendant au
| > | moins dix ans avant de passer aux langages évolués.

| > Tu comptes le C comme de l'assembleur ou comme un langage évolué.
| Peut-on définir un langage évolué comme un langage dans lequel le
| code objet généré est entièrement prévisible ? C'est l'idée que je
| m'en fais, sans grande conviction.

Oh, dans ce thread, James a fait part d'une expérience personnelle --
qui est ce que j'ai citée.
Je voulais l'intégrer avec les autres parts dont j'ai connaissance,
soit parce qu'il les dites publiquement, soit parce qu'il me les a
dites. Et cela n'arrivait pas a rentrer correctement, alors je voulais
savoir, ce que je pouvais virer, ajouter, comprimer ou elargir.
Je n'avais nullement l'intention de me lancer dans un debat de
definition de langage evolué. Juste ce qu'il entendait par langage
evolué suffisait pour moi pour faire face au puzzle que j'avais.


Je ne sais pas où est le problème. Mon CV est disponible en ligne, pour
ceux que ça intéresse. En ce qui concerne l'assembleur, j'ai programmé
exclusivement en assembleur de 1973 à 1979 (mais une partie de
l'assembleur, c'était bien un compilateur et une bibliothèque Fortran),
puis largement en assembleur jusqu'en 1985.

Mon premier contact au C date de 82, quand j'ai dû implémenter une
bibliothèque de base (printf, etc.) pour un compilateur C.
L'implémentation même était en revanche largement en assembleur.

Ça ne concerne que mes activités professionnelles. À titre de curiosité
d'adolescent, j'ai appris l'assembleur 1401 en 1965, mais je m'en suis
jamais réelement servi. Mes premiers contacts avec C++ était aussi
privé, aux alentours de 1987.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Gabriel Dos Reis
writes:

[...]

| D'après la rationnale (http://www.lysator.liu.se/c/rat/title.html) :
|
| Pointers to functions may be used either as (*pf)() or as pf(). The
| latter construct, not sanctioned in the Base Document, appears in
| some present versions of C, is unambiguous, invalidates no old code,
| and can be an important shorthand. The shorthand is useful for

[...]

| En ce qui concerne la motivation de base, je suis prèsque sûr que
| l'extention était assez répandue -- je m'en souviens de son existance

Pas dans le compilateur de Dennis Ritchie, ni dans CFront (ou ses
ancêtres) quand l'invention a été introduite. :-)

| bien avant C90, et j'avoue avoir été étonné quand Gaby a dit qu'elle
| n'était pas dans K&R 1.

Ben, dans la passage que tu cites, il est bien marqué que cela
n'était pas autorisé dans le « Base document » -- qui dérivait de C K+R.

[...]

| > oui mais, je ne crois pas que cette invention était quelque chose qui
| > ait fait unanimité dans la communauté C++ -- surtout chez ceux qui
| > sont attachés à la notion de type.
|
| Je ne crois pas qu'elle ait fait l'unanimité dans la communauté C non
| plus. Le problème, c'est que c'était une pratique existante avec
| certains compilateurs.

« le problème » ? Quel problème ?

Certainement, il y a plain d'autres trucs dans « certains » autres
compilateurs...

-- Gaby
Avatar
Gabriel Dos Reis
writes:

| Je ne sais pas où est le problème. Mon CV est disponible en ligne, pour

En 1998, lorsque tu m'as donné une version moins formelle de ton CV
par mail, tu m'as dit que tu as commencé le C en 1974-1975. Mais, si
tu as voulu dire 82, alors je n'ai aucun problème à retrécir certaines
périodes.

| ceux que ça intéresse. En ce qui concerne l'assembleur, j'ai programmé
| exclusivement en assembleur de 1973 à 1979 (mais une partie de
| l'assembleur, c'était bien un compilateur et une bibliothèque Fortran),
| puis largement en assembleur jusqu'en 1985.
|
| Mon premier contact au C date de 82, quand j'ai dû implémenter une
| bibliothèque de base (printf, etc.) pour un compilateur C.
|
| L'implémentation même était en revanche largement en assembleur.
|
| Ça ne concerne que mes activités professionnelles. À titre de curiosité
| d'adolescent, j'ai appris l'assembleur 1401 en 1965, mais je m'en suis
| jamais réelement servi. Mes premiers contacts avec C++ était aussi
| privé, aux alentours de 1987.

Une version que je possédais jusqu'à présent aux alentours de 1990. Je
remets ma base de données à jour.

-- Gaby
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
writes:

[...]

| D'après la rationnale (http://www.lysator.liu.se/c/rat/title.html) :

| Pointers to functions may be used either as (*pf)() or as pf().
| The latter construct, not sanctioned in the Base Document,
| appears in some present versions of C, is unambiguous,
| invalidates no old code, and can be an important shorthand. The
| shorthand is useful for

[...]

| En ce qui concerne la motivation de base, je suis prèsque sûr que
| l'extention était assez répandue -- je m'en souviens de son
| existance

Pas dans le compilateur de Dennis Ritchie, ni dans CFront (ou ses
ancêtres) quand l'invention a été introduite. :-)


Je ne connais pas le compilateur de Dennis Ritchie. Les compilateurs C
dont je me suis servi ont été tous dérivés de pCC de Johnson, par
Berkley. Mais à vrai dire, je ne me souviens plus dans quel compilateur
je l'ai vu, ou où j'en ai entendu parlé. Vue que je ne l'aimais pas, je
n'ai pas trop essayé. N'empêche que les gourous de qui j'ai appris le C
croyaient que c'était permis, généralement, et s'en servait allegrément
dans leur propre code.

Quant à CFront, c'était du C++. Où on a toujours pris les types plus au
sérieux qu'en C.

| bien avant C90, et j'avoue avoir été étonné quand Gaby a dit qu'elle
| n'était pas dans K&R 1.

Ben, dans la passage que tu cites, il est bien marqué que cela n'était
pas autorisé dans le « Base document » -- qui dérivait de C K+R.


Oui, mais je n'ai cherché ce passage qu'après avoir lu ton posting.

Comme j'ai dit, j'avais toujours « supposé » que c'était en K&R. Mais
sans m'en souvenir précisément de l'y avoir lu. Quand tu l'as dit, ça
m'a surpris -- mais je ne me suis pas douté de ta parole.

[...]

| > oui mais, je ne crois pas que cette invention était quelque chose
| > qui ait fait unanimité dans la communauté C++ -- surtout chez ceux
| > qui sont attachés à la notion de type.

| Je ne crois pas qu'elle ait fait l'unanimité dans la communauté C
| non plus. Le problème, c'est que c'était une pratique existante avec
| certains compilateurs.

« le problème » ? Quel problème ?

Certainement, il y a plain d'autres trucs dans « certains » autres
compilateurs...


Je sais, et il y a pas mal de code que la première norme C a cassé.
N'empêche que je ne vois pas d'autre raison qui les aurait fait
considérer l'extension.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Michel Michaud
Dans news:,
D'après la rationnale (http://www.lysator.liu.se/c/rat/title.html) :


Merci pour cette adresse James... Je pensais l'avoir (ou une autre
semblable), mais il semble que non...

On remarque que même pour le comité C, la forme usuelle (ou
« conventionnelle »), c'est (*pf)().


Effectivement, mais j'avais toujours compris qu'elle était
simplement préférée et non la seule initialement.

En ce qui concerne la motivation de base, je suis prèsque sûr que
l'extention était assez répandue -- je m'en souviens de son
existance bien avant C90, et j'avoue avoir été étonné quand Gaby a
dit qu'elle n'était pas dans K&R 1.


Toi aussi ? Bien :-)

Je n'ai fait du C pré-ANSI que pendant 6-7 ans, mais il me semble
bien que mon compilateur acceptait pf() quand j'ai commencé à en
faire usage. Était-ce un compilateur ANSI C ou simplement une
possibilité offerte par mon compilateur, je ne sais pas...

[...]
Je ne crois pas qu'elle ait fait l'unanimité dans la communauté C
non plus. Le problème, c'est que c'était une pratique existante avec
certains compilateurs.


J'avoue que j'ai toujours trouvé le déréférencement (et la prise
d'adresse) explicite un peu artificiel. L'analogie avec les
tableaux me semble vraiment naturelle. Est-ce que j'aurais eu une
façon de voir qui vient d'autre langage ? Je ne me souviens plus
du passage de fonction en Pascal... Quand même :

int UneFct(int n) { ... }
int v[10];

void Naturelle(int v[], int F(int)) // Pointeurs implicites
{
v[2]= F(v[4]);
}

void MoinsNaturelle(int *pv, int (*pF)(int)) // Explicites
{
v[2]= (*pF)(v[4]); // Et non pas (*v)[2], etc.
}

int main()
{
Naturelle(v, UneFct);
MoinsNaturelle(v, &UneFct); // &v ? ...

// N.B. Évidemment on peut appeler les deux fonctions
// de la même façon...
}

En fait, si j'avais Ritchie devant moi, je lui demanderais
pourquoi, dans son langage original, on peut écrire v pour
&v[0] au lieu d'exiger & comme pour les fonctions... La
solution ANSI me semble plus uniforme.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Avatar
Gabriel Dos Reis
writes:

| Gabriel Dos Reis wrote in message
| news:...
| > writes:
|
| > [...]
|
| > | D'après la rationnale (http://www.lysator.liu.se/c/rat/title.html) :
|
| > | Pointers to functions may be used either as (*pf)() or as pf().
| > | The latter construct, not sanctioned in the Base Document,
| > | appears in some present versions of C, is unambiguous,
| > | invalidates no old code, and can be an important shorthand. The
| > | shorthand is useful for
|
| > [...]
|
| > | En ce qui concerne la motivation de base, je suis prèsque sûr que
| > | l'extention était assez répandue -- je m'en souviens de son
| > | existance
|
| > Pas dans le compilateur de Dennis Ritchie, ni dans CFront (ou ses
| > ancêtres) quand l'invention a été introduite. :-)
|
| Je ne connais pas le compilateur de Dennis Ritchie. Les compilateurs C
| dont je me suis servi ont été tous dérivés de pCC de Johnson, par
| Berkley. Mais à vrai dire, je ne me souviens plus dans quel compilateur
| je l'ai vu, ou où j'en ai entendu parlé. Vue que je ne l'aimais pas, je
| n'ai pas trop essayé. N'empêche que les gourous de qui j'ai appris le C
| croyaient que c'était permis, généralement, et s'en servait allegrément
| dans leur propre code.

J'ai toujours cru que tu as appris ton C du K+R 1 -- et aucun des
deux s'en servaient allègrement.

| Quant à CFront, c'était du C++. Où on a toujours pris les types plus au
| sérieux qu'en C.

Cela ne paraît pas évident mais Cfront a l'époque payait une attention
particulière à la compatibilité avec C

[...]

| Je sais, et il y a pas mal de code que la première norme C a cassé.
| N'empêche que je ne vois pas d'autre raison qui les aurait fait
| considérer l'extension.

la même que celle qui les as considérer void* -> T* ?

-- Gaby
Avatar
Gabriel Dos Reis
"Michel Michaud" writes:

| Je n'ai fait du C pré-ANSI que pendant 6-7 ans, mais il me semble
| bien que mon compilateur acceptait pf() quand j'ai commencé à en
| faire usage. Était-ce un compilateur ANSI C ou simplement une
| possibilité offerte par mon compilateur, je ne sais pas...

J'utilisais static_cast<> avant que la norme C++ ne soit publiée en
1998...

| [...]
| > Je ne crois pas qu'elle ait fait l'unanimité dans la communauté C
| > non plus. Le problème, c'est que c'était une pratique existante avec
| > certains compilateurs.
|
| J'avoue que j'ai toujours trouvé le déréférencement (et la prise
| d'adresse) explicite un peu artificiel. L'analogie avec les
| tableaux me semble vraiment naturelle.

C'est curieux, je trouve l'analogie avec les tableaux fallacieuse.

[...]

| En fait, si j'avais Ritchie devant moi, je lui demanderais
| pourquoi, dans son langage original, on peut écrire v pour
| &v[0] au lieu d'exiger & comme pour les fonctions... La
| solution ANSI me semble plus uniforme.

???

-- Gaby
Avatar
Michel Michaud
Dans news:, Gabriel Dos
"Michel Michaud" writes:

Je n'ai fait du C pré-ANSI que pendant 6-7 ans, mais il me semble
bien que mon compilateur acceptait pf() quand j'ai commencé à en
faire usage. Était-ce un compilateur ANSI C ou simplement une
possibilité offerte par mon compilateur, je ne sais pas...


J'utilisais static_cast<> avant que la norme C++ ne soit publiée en
1998...


Moi aussi. Et string et vector et... :-)

C'est curieux, je trouve l'analogie avec les tableaux fallacieuse.


C'est ton droit.

En fait, si j'avais Ritchie devant moi, je lui demanderais
pourquoi, dans son langage original, on peut écrire v pour
&v[0] au lieu d'exiger & comme pour les fonctions... La
solution ANSI me semble plus uniforme.


???


Ton interrogation signifie quoi dans ce cas-ci ? Tu dois t'ennuyer
un peu (ça me surprend) si tu veux qu'on essaie de deviner. Mais
bon, on peut jouer. Je vais supposer que tu ne comprends pas mon
questionnement, mais évidemment tu me diras que ce n'est pas que
tu voulais dire... Je reformule quand même et je pose une question
sérieuse, qui m'intéresse. Pourquoi a-t-on besoin de la conversion
implicite du nom d'un vecteur en adresse de son premier élément,
plus que de la conversion du nom d'une fonction en adresse de
cette fonction ?

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


Avatar
Michel Michaud
Dans news:, Gabriel Dos
"Michel Michaud" writes:

Je n'ai fait du C pré-ANSI que pendant 6-7 ans, mais il me semble
bien que mon compilateur acceptait pf() quand j'ai commencé à en
faire usage. Était-ce un compilateur ANSI C ou simplement une
possibilité offerte par mon compilateur, je ne sais pas...


J'utilisais static_cast<> avant que la norme C++ ne soit publiée en
1998...


Moi aussi. Et string et vector et... :-)

C'est curieux, je trouve l'analogie avec les tableaux fallacieuse.


C'est ton droit.

En fait, si j'avais Ritchie devant moi, je lui demanderais
pourquoi, dans son langage original, on peut écrire v pour
&v[0] au lieu d'exiger & comme pour les fonctions... La
solution ANSI me semble plus uniforme.


???


Ton interrogation signifie quoi dans ce cas-ci ? Tu dois t'ennuyer
un peu (ça me surprend) si tu veux qu'on essaie de deviner. Mais
bon, on peut jouer. Je vais supposer que tu ne comprends pas mon
questionnement, mais évidemment tu me diras que ce n'est pas que
tu voulais dire... Je reformule quand même et je pose une question
sérieuse, qui m'intéresse. Pourquoi a-t-on besoin de la conversion
implicite du nom d'un vecteur en adresse de son premier élément,
plus que de la conversion du nom d'une fonction en adresse de
cette fonction ?

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


1 2 3 4 5