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

C++, pointeurs de fonctions, fonctions membres, threads et signaux

39 réponses
Avatar
vincent.lecoq
Je cherche a develloper une petite librairie en C++ sous Linux (et/ou
BSD ).
Elle a besoin des appels systeme signal et pthread_create.
La fonction associee a mon signal est un membre d'une des classes de
ma librairie, elles est appelee en interne par celle ci pour detacher
un process puis restaurer l'environement d'origine. or g++ (et le C++
en general) m'interdisent de passer cette fonction a signal car elle
est du type MaClasse::ma_fonction et comme cette fonction doit se
servir de certaines variables propres a l'instance de la classe
appelante, je ne peux par l'exterioriser ...

Comment faire ?

9 réponses

1 2 3 4
Avatar
Gabriel Dos Reis
drkm writes:

| Gabriel Dos Reis writes:
|
| > writes:
|
| > [...]
|
| > | > Il me semble avoir déjà utilisé une telle chose, sans avertissement.
|
| > | C'est possible. CFront ne faisait pas la distinction. Zortech, en
| > | revanche, oui, puisque la séquence d'appel pour une fonction C++ n'était
| > | pas la même que pour une fonction C. Le comité n'a voulu interdire les
| > | implémentations comme Zortech (qui est quand même l'implémentation la
| > | plus raisonable sur une architecture Intel). Du coup, le linkage fait
| > | partie du type de la fonction.
|
| > Ce qui est une kolossale erreur.
|
| Quoi ? De faire intervenir le linkage dans le type d'une fonction ?

Oui.

La notion de linkage est une vielle relique ; tant qu'on ne l'applique
qu'aux noms, ça va encore, mais commencer à le mettre dans un type est
une erreur.

-- Gaby
Avatar
Gabriel Dos Reis
"Alain Naigeon" writes:

| "drkm" a écrit dans le message news:
|
| > Heu, au fait, j'ai maintenant du mal à comprendre l'article de Gaby
|
| C'est une sérieuse garantie d'authenticité :-) :-)

Ah ?

-- Gaby
Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

La notion de linkage est une vielle relique ; tant qu'on
ne l'applique qu'aux noms, ça va encore, mais commencer à
le mettre dans un type est une erreur.


Je ne suis pas aussi sûr. Il me semble normal que le
linkage "C", "C++" ou autre fasse partie du type d'une
fonction (ça change le code à générer) . Mais le linkage
interne ou externe non.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Gabriel Dos Reis
Jean-Marc Bourguet writes:

| Gabriel Dos Reis writes:
|
| > La notion de linkage est une vielle relique ; tant qu'on
| > ne l'applique qu'aux noms, ça va encore, mais commencer à
| > le mettre dans un type est une erreur.
|
| Je ne suis pas aussi sûr. Il me semble normal que le
| linkage "C", "C++" ou autre fasse partie du type d'une
| fonction (ça change le code à générer) . Mais le linkage
| interne ou externe non.

Il y a deux chose distinctes :

(1) linkage ;
(2) convention d'appel (« language specification » en standardais).

Pour le linkage, c'est un machin qui était plus ou moins imposé par C
et la technologie de lieur d'il y a plus de 30 ans et qu'on traîne
toujours comme un boulet.

Lorsque la convention d'appel (e.g. « extern "C" ») a été introduite
en C++, cela n'est pas pour changer le type des fonctions (ou des
variables), mais c'est pour spécifier la convention d'appel.
Plus précisément, il a été introduit comme un mécanisme de glue pour
lier du code C++ avec une partie de programme écrit dans un langage X.
Mais comme il n'est pas possible d'exprimer le langage X directement
en C++, il est une erreur de modifier le type d'une entité en se basant
uniquement sur la spécification de langage « extern "X" ». Cette
spécification n'est pas à l'adresse du système de type. Il est à
l'adresse du générateur de code. D'ailleurs dans un bloc extern "X",
on écrit pas du X, on écrit du C++.

(On obtient un même problème similaire lorsque les gens ont commencé à
vouloir exprimer l'aliasing avec « restrict ». Le système de type
C++/C ne peut pas exprimer cela correctement. Donc le mettre là est
une erreur).

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

| Gabriel Dos Reis writes:

| > La notion de linkage est une vielle relique ; tant qu'on
| > ne l'applique qu'aux noms, ça va encore, mais commencer à
| > le mettre dans un type est une erreur.

| Je ne suis pas aussi sûr. Il me semble normal que le
| linkage "C", "C++" ou autre fasse partie du type d'une
| fonction (ça change le code à générer) . Mais le linkage
| interne ou externe non.

Il y a deux chose distinctes :

(1) linkage ;
(2) convention d'appel (« language specification » en standardais).


(En effet. Je me suis trompé de mot. C'est la convention d'appel dont on
parle ici, et non le linkage.)

Pour le linkage, c'est un machin qui était plus ou moins imposé par C
et la technologie de lieur d'il y a plus de 30 ans et qu'on traîne
toujours comme un boulet.

Lorsque la convention d'appel (e.g. « extern "C" ») a été introduite
en C++, cela n'est pas pour changer le type des fonctions (ou des
variables), mais c'est pour spécifier la convention d'appel. Plus
précisément, il a été introduit comme un mécanisme de glue pour lier
du code C++ avec une partie de programme écrit dans un langage X.
Mais comme il n'est pas possible d'exprimer le langage X directement
en C++, il est une erreur de modifier le type d'une entité en se
basant uniquement sur la spécification de langage « extern "X" ».
Cette spécification n'est pas à l'adresse du système de type. Il est à
l'adresse du générateur de code. D'ailleurs dans un bloc extern "X",
on écrit pas du X, on écrit du C++.


C'est probablement vrai de point de vue théorique. Je n'ai rien contre,
mais... Il faut bien qu'un pointeur à une fonction soit lié à une
convention d'appel, et à une seule, et que le programmeur ne peut pas
affecter l'adresse d'une fonction « extern "C++" » à un pointeur
«@extern "C" ». Intuititivement, je dirais que la façon naturelle
d'exprimer cette contrainte, c'est à travers le système de types. Mais
je suis ouvert à toute autre suggestion.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Gabriel Dos Reis
writes:

[...]

| > Lorsque la convention d'appel (e.g. « extern "C" ») a été introduite
| > en C++, cela n'est pas pour changer le type des fonctions (ou des
| > variables), mais c'est pour spécifier la convention d'appel. Plus
| > précisément, il a été introduit comme un mécanisme de glue pour lier
| > du code C++ avec une partie de programme écrit dans un langage X.
| > Mais comme il n'est pas possible d'exprimer le langage X directement
| > en C++, il est une erreur de modifier le type d'une entité en se
| > basant uniquement sur la spécification de langage « extern "X" ».
| > Cette spécification n'est pas à l'adresse du système de type. Il est à
| > l'adresse du générateur de code. D'ailleurs dans un bloc extern "X",
| > on écrit pas du X, on écrit du C++.
|
| C'est probablement vrai de point de vue théorique.

Non seulement, c'est légitime du point de vue théorique, mais aussi du
point de vue pratique. Par exemple, std::ptr_fun() ne peut pas être
utilisé avec std::strlen() de manière portable. Ce n'est pas seulement,
une erreur, mais c'est également une faute lorsqu'on considère la
bibliothèque standard, ou la programmation générique par exemple.

| Je n'ai rien contre,
| mais... Il faut bien qu'un pointeur à une fonction soit lié à une
| convention d'appel, et à une seule, et que le programmeur ne peut pas
| affecter l'adresse d'une fonction « extern "C++" » à un pointeur
| «@extern "C" ».

D'abord il vaut virer cette notion de pointeur « extern "C" » et
pointeur « extern "C++" ». Cela n'a pas grand sens -- d'accord tu peux
reciter la norme, mais ce que je suis en train de dire, c'est que
cette décision a été prise sans bien en mesurer l'impact (et c'est
loin d'être le seul ; pour une raison ou une autre Core me donne
l'impression d'être fâché avec les types de fonctions).

Supposons que j'ai une fonction foo() avec une convention d'appel
« X ». Si je l'appelle lexicalement, alors le compilateur a les
informations nécessaires pour « réorganiser » l'appel de manière à
satisfaire les contraintes idoines. Donc pas de problème là.
Si je prends l'addresse d'une telle fonction, le compilateur est
moralement obligé d'en avoir une définition off-line. Mais, dans ce
cas, le compilateur peut très bien générer un thunk qui réorganise les
arguments et branche sur le code effectif. Il n'y a rien de sorcier,
rien que de l'ordinaire -- les thunks sont déjà utilisés pour
implémenter les « covariante returns », fonctions virtuelles de
classes de bases virtuelles, l'héritage multiple.

| Intuititivement, je dirais que la façon naturelle
| d'exprimer cette contrainte, c'est à travers le système de types. Mais

Mais pas celui de C++ -- il n'est pas assez puissant pouor ça.

| je suis ouvert à toute autre suggestion.

Le problème de fond, c'est que si on a une fonction à convention
d'appel « X », et qu'on l'invoque par un pointeur sur une fonction,
elle risque de ne pas recevoir le bon nombre d'arguments ou de les
recevoir dans le mauvais ordre. Mais ça c'est un problème de
génération de code. Là où l'adresse de la fonction est prise, le
compilateur le sait et peut donc générer un thunk pour ça. Il n'est
nul besoin de corrompre le système de type.

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

[...]

| > Lorsque la convention d'appel (e.g. « extern "C" ») a été
| > introduite en C++, cela n'est pas pour changer le type des
| > fonctions (ou des variables), mais c'est pour spécifier la
| > convention d'appel. Plus précisément, il a été introduit comme un
| > mécanisme de glue pour lier du code C++ avec une partie de
| > programme écrit dans un langage X. Mais comme il n'est pas
| > possible d'exprimer le langage X directement en C++, il est une
| > erreur de modifier le type d'une entité en se basant uniquement
| > sur la spécification de langage « extern "X" ». Cette
| > spécification n'est pas à l'adresse du système de type. Il est à
| > l'adresse du générateur de code. D'ailleurs dans un bloc extern
| > "X", on écrit pas du X, on écrit du C++.

| C'est probablement vrai de point de vue théorique.

Non seulement, c'est légitime du point de vue théorique, mais aussi du
point de vue pratique. Par exemple, std::ptr_fun() ne peut pas être
utilisé avec std::strlen() de manière portable. Ce n'est pas
seulement, une erreur, mais c'est également une faute lorsqu'on
considère la bibliothèque standard, ou la programmation générique par
exemple.


La réponse à ce point précis, c'est que la norme ne doit pas permettre
que strlen soit une fonction « extern "C" »:-). Mais je vois où tu veux
en venir.

| Je n'ai rien contre, mais... Il faut bien qu'un pointeur à une
| fonction soit lié à une convention d'appel, et à une seule, et que
| le programmeur ne peut pas affecter l'adresse d'une fonction «
| extern "C++" » à un pointeur « extern "C" ».

D'abord il vaut virer cette notion de pointeur « extern "C" » et
pointeur « extern "C++" ». Cela n'a pas grand sens -- d'accord tu peux
reciter la norme, mais ce que je suis en train de dire, c'est que
cette décision a été prise sans bien en mesurer l'impact (et c'est
loin d'être le seul ; pour une raison ou une autre Core me donne
l'impression d'être fâché avec les types de fonctions).


La décision a été prise surtout, je crois, en fonction des problèmes de
l'implémentation. Le fait est qu'il existe des implémentations où les
conventions d'appel de C ne sont pas les mêmes que celles de C++. Et
évidemment, l'intention allait plus loin -- logiquement, étant donné
leur contexte, et Sun CC et g++ doivent aussi supporter un « extern
"Fortran" » et un « extern "Ada" ». Or, dans ce cas-là, c'est quasiment
impossible d'utiliser les mêmes conventions d'appel.

Et comme tu dis, c'est probable qu'ils n'ont pas vue toutes les
conséquences. Les conséquences sur l'implémentation, c'est
claires. (C'est plus de travail.) Les conséquences en ce qui concerne la
méta-programmation, c'est moins claires -- on n'avait pas beaucoup
d'expérience en méta-programmation à l'époque.

Supposons que j'ai une fonction foo() avec une convention d'appel
« X ». Si je l'appelle lexicalement, alors le compilateur a les
informations nécessaires pour « réorganiser » l'appel de manière à
satisfaire les contraintes idoines. Donc pas de problème là. Si je
prends l'addresse d'une telle fonction, le compilateur est moralement
obligé d'en avoir une définition off-line. Mais, dans ce cas, le
compilateur peut très bien générer un thunk qui réorganise les
arguments et branche sur le code effectif. Il n'y a rien de sorcier,
rien que de l'ordinaire -- les thunks sont déjà utilisés pour
implémenter les « covariante returns », fonctions virtuelles de
classes de bases virtuelles, l'héritage multiple.


L'idée d'une trampoline m'est venue aussi à l'esprit. Il n'y a qu'un
point où je ne suis pas trop sûr. Considérons :

extern "C" void funcC( void (*pf)( void* ) ) ;

void
funcCPP( void (*pf)( void* ) )
{
funcC( pf ) ;
}

Comment implémenter funcCPP si les conventions d'appel sont
différentes ? Il faudrait à partir d'un pointeur à une fonction aux
conventions C++ générer un pointeur à une fonction aux conventions C. En
somme, encore une trampoline. (Ce qui veut dire éventuellement une
trampoline qui convertit C en C++ pour appeler une trampoline qui
convertit C++ en C.)

Mais enfin, je crois que c'est faisable. Ça ajoute un certain coût aux
implémentaions où les conventions diffèrent, mais seulement dans des cas
assez particuliers, et ces implémentations sont rares, je crois.

| Intuititivement, je dirais que la façon naturelle d'exprimer cette
| contrainte, c'est à travers le système de types. Mais

Mais pas celui de C++ -- il n'est pas assez puissant pouor ça.

| je suis ouvert à toute autre suggestion.

Le problème de fond, c'est que si on a une fonction à convention
d'appel « X », et qu'on l'invoque par un pointeur sur une fonction,
elle risque de ne pas recevoir le bon nombre d'arguments ou de les
recevoir dans le mauvais ordre. Mais ça c'est un problème de
génération de code. Là où l'adresse de la fonction est prise, le
compilateur le sait et peut donc générer un thunk pour ça. Il n'est
nul besoin de corrompre le système de type.


D'accord. Tu m'as convaincu.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

Jean-Marc Bourguet writes:
| Gabriel Dos Reis writes:

|
| > La notion de linkage est une vielle relique ; tant qu'on
| > ne l'applique qu'aux noms, ça va encore, mais commencer
| > à le mettre dans un type est une erreur.

[...]

(On obtient un même problème similaire lorsque les gens
ont commencé à vouloir exprimer l'aliasing avec « restrict
». Le système de type C++/C ne peut pas exprimer cela
correctement. Donc le mettre là est une erreur).


J'ai malheureusement pas le temps (je suis en congé...:-) de
réfléchir à ça comme je le voudrais. J'aimerais quand même
que tu précises un point. Tu écris ci-dessus que le
linkage, les conventions d'appel et restrict ne devraient
pas se retrouver dans le système de type. Est-ce que pour
les trois ton affirmation est limitée au C++ ou bien ton
affirmation est à portée plus générale ?

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Gabriel Dos Reis
Jean-Marc Bourguet writes:

[...]

| > (On obtient un même problème similaire lorsque les gens
| > ont commencé à vouloir exprimer l'aliasing avec « restrict
| > ». Le système de type C++/C ne peut pas exprimer cela
| > correctement. Donc le mettre là est une erreur).
|
| J'ai malheureusement pas le temps (je suis en congé...:-) de
| réfléchir à ça comme je le voudrais. J'aimerais quand même
| que tu précises un point. Tu écris ci-dessus que le
| linkage, les conventions d'appel et restrict ne devraient
| pas se retrouver dans le système de type. Est-ce que pour
| les trois ton affirmation est limitée au C++ ou bien ton
| affirmation est à portée plus générale ?

C'est le C++.

-- Gaby
1 2 3 4