OVH Cloud OVH Cloud

Conventions d'appel (__cdecl,__fastcall) et norme C++

3 réponses
Avatar
Gilles
Bonjour,

Un de mes clients utilise mon SDK (sous VC++/windows) avec la convention
d'appel "fastcall". Or, lors de la compilation de mon SDK je n'ai pas
spécifié explicitement de convention d'appel dans la déclaration de mes
fonctions. La convention d'appel par défaut (__cdecl) est donc utilisée. Du
coup, ça plante à l'exécution.

En spécifiant explicitement dans la déclaration de mes fonctions la
convention d'appel que j'utilise, le problème disparaît.
En clair, si dans les headers de mon SDK j'écris:
void __cdecl Foo();
au lieu de:
void Foo();
ça fonctionne quelle que soit la convention d'appel utilisée par mon client.

Cette solution semble donc intéressante pour VC++/windows mais est-elle
généralisable à toutes les plateformes et à tous les compilateurs ?
Ces conventions d'appel sont-elles régies par la norme C++ ?
Est-ce une pratique répendue pour les compilateurs que d'utiliser des
conventions d'appel spécifiques ?
Comment traite-t-on ce genre de problème habituellement ?

Merci d'avance,

Gilles.

3 réponses

Avatar
Fabien LE LEZ
On Thu, 20 Jan 2005 12:48:14 +0100, "Gilles" :

Ces conventions d'appel sont-elles régies par la norme C++ ?


Etant donné que les noms commençant par "_" (sauf quelques exceptions
dont j'ai oublié le détail) sont censés être réservés à
l'implémentation, j'en doute.

Un bon vieux
extern "C"
ne conviendrait-il pas ?


--
;-)

Avatar
Jean-Marc Bourguet
Fabien LE LEZ writes:

On Thu, 20 Jan 2005 12:48:14 +0100, "Gilles" :

Ces conventions d'appel sont-elles régies par la norme C++ ?


Etant donné que les noms commençant par "_" (sauf quelques exceptions
dont j'ai oublié le détail) sont censés être réservés à
l'implémentation, j'en doute.

Un bon vieux
extern "C"
ne conviendrait-il pas ?


A priori, non.

En fait ces __fastcall et autres __cdecl s'exprimeraient mieux dans
l'esprit de la norme avec des blocs extern "C++ fastcall" et extern
"C++ cdecl" qu'avec des annotations. Suivant comment est programme
VC++ (je ne l'utilise pas), il est possible qu'un extern "C++" fasse
ce qu'il faut (et extern "C++" est normalise et devrait etre accepte
par tous les compilateurs).

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
kanze
Gilles wrote:

Un de mes clients utilise mon SDK (sous VC++/windows) avec la
convention d'appel "fastcall". Or, lors de la compilation de
mon SDK je n'ai pas spécifié explicitement de convention
d'appel dans la déclaration de mes fonctions. La convention
d'appel par défaut (__cdecl) est donc utilisée. Du coup, ça
plante à l'exécution.

En spécifiant explicitement dans la déclaration de mes
fonctions la convention d'appel que j'utilise, le problème
disparaît. En clair, si dans les headers de mon SDK j'écris:

void __cdecl Foo();
au lieu de:
void Foo();
ça fonctionne quelle que soit la convention d'appel utilisée
par mon client.


C-à-d en fait que tu spécifies explicitement dans l'en-tête la
convention dont tu t'es servi implicitement lors de la
compilation. C'est une précaution assez sage si tu livres des
bibliothèques pour Windows à des clients externes.

Cette solution semble donc intéressante pour VC++/windows mais
est-elle généralisable à toutes les plateformes et à tous les
compilateurs ?


Pas du tout. Ça crée une erreur de syntaxe sur la plupart des
compilateurs. La présense de ces déclarations sous Windows est
liée à une lourde historique, qui débute à cause des
particularités de l'architecture Intel. En général, sur des
autres architectures, il n'y a qu'une seule convention d'appel ;
il n'y a aucune raison pour plus (dans un langage donné).

Ces conventions d'appel sont-elles régies par la norme C++ ?


D'une manière : elle n'existe pas dans la norme. Un compilateur
conforme est obligé à émettre un message d'erreur s'elles
apparaissent.

Est-ce une pratique répendue pour les compilateurs que
d'utiliser des conventions d'appel spécifiques ?


Sur architecture Intel, c'est essentielle, mais on aurait pu
imaginer quelque chose de plus dans l'esprit de la norme, par
exemple :

extern "C++ fastdecl" ...

Mais déjà dans la norme C, il a été décrété que des extensions
doivent commencer par __. En G++, par exemple, on a des options
semblable au moyen de __attribute__, et les options vont jusqu'à
permettre la spécification de combien de paramètres qu'on passe
dans des régistres. Histoire de rendre la portabilité encore
plus difficile, __attribute__ suit le nom de la fonction.

En général, on évite ce genre de chose dans un code portable ;
son utilisation est assez rare en g++, par exemple. Mais plus
important, autant que je sache, il n'y a pas d'option de
compilateur pour g++ qui en change le défaut.

Comment traite-t-on ce genre de problème habituellement ?


La plus souvent, au moyen d'un macro :

#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#define CALLTYPE __cdecl
#else
#define CALLTYPE
#endif

Une technique semblable sert souvent pour les
déclarations/définitions qui vont se rétrouver dans une DLL.

Une autre alternative serait simplement de livrer trois versions
de ta bibliothèque, compilées avec /Gd, /Gr ou /Gz.
L'utilisateur est alors libre d'utiliser la version qui lui
convient, en fonction de ses défauts.

--
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