78 votes

__cdecl ou __stdcall sous Windows?

Je suis actuellement à l'élaboration d'une bibliothèque C++ pour Windows qui sera distribuée sous forme d'une DLL. Mon objectif est de maximiser le binaire de l'interopérabilité; plus précisément, les fonctions dans ma DLL doit être utilisable à partir du code compilé avec plusieurs versions de MSVC++ et MinGW sans avoir à recompiler le DLL. Cependant, je suis confus au sujet de la convention d'appel est le meilleur, cdecl ou stdcall.

Parfois, j'entends des phrases comme: "la convention d'appel C est la seule garantie d'être le même à travers les compilateurs", qui contraste avec des déclarations comme "Il y a quelques variations dans l'interprétation de l' cdecl, en particulier dans la façon de valeurs de retour". Cela ne semble pas arrêter certains de la bibliothèque de développeurs (comme libsndfile) pour utiliser la convention d'appel C dans les Dll qu'ils distribuent, sans que les problèmes soient visibles.

D'autre part, l' stdcall convention d'appel semble être bien défini. De ce que j'ai dit, toutes les Fenêtres des compilateurs sont fondamentalement nécessaires à la suivre parce que c'est la convention utilisée pour Win32 et COM. Ceci est basé sur l'hypothèse qu'un compilateur Windows sans Win32/COM soutien ne serait pas très utile. Beaucoup de fragments de code posté sur des forums de déclarer des fonctions comme l' stdcall mais je n'arrive pas à trouver un seul post qui explique clairement pourquoi.

Il y a trop d'informations contradictoires là-bas, et chaque recherche que j'ai exécutez me donne des réponses différentes qui n'aident pas vraiment à me décider entre les deux. Je suis à la recherche de claire, détaillée raisonnée explication des raisons pour lesquelles je devrais choisir entre l'un ou l'autre (ou pourquoi les deux sont équivalents).

Notez que cette question ne s'applique pas seulement à la "classique" de fonctions, mais aussi pour fonction membre virtuelle des appels, depuis plus de code client fera l'interface avec ma DLL à travers des "interfaces", pur classes virtuelles (suivant les modèles décrits par exemple ici et ).

75voto

e-t172 Points 4408

J'ai juste fait quelques essais du monde réel (la compilation de la Dll et applications avec MSVC++ et MinGW, puis les mélanger). Comme il apparaît, j'ai eu de meilleurs résultats avec l' cdecl convention d'appel.

Plus précisément: le problème avec stdcall , c'est que MSVC++ mangles noms dans la DLL table d'exportation, même lors de l'utilisation d' extern "C". Par exemple foo devient _foo@4. Cela se produit uniquement lors de l'utilisation d' __declspec(dllexport), et non pas lors de l'utilisation d'un fichier DEF; cependant, DEF fichiers sont d'un entretien sans tracas à mon avis, et je ne veux pas les utiliser.

Le MSVC++ name mangling, deux problèmes se posent:

  • À l'aide de GetProcAddress sur la DLL est un peu plus compliqué;
  • MinGW par défaut n'est pas ajouter une undescore à la ornée des noms (par exemple, MinGW utilisera foo@4 au lieu de _foo@4), ce qui complique l'établissement de liens. Aussi, il présente le risque de voir les "non-soulignent les versions de" Dll et les applications de pop up dans la nature qui sont incompatibles avec le "trait de soulignement versions".

J'ai essayé de l' cdecl convention: l'interopérabilité entre MSVC++ et MinGW fonctionne parfaitement, out-of-the-box, et les noms de séjour non décoré dans le DLL table d'exportation. Il fonctionne même pour les méthodes virtuelles.

Pour ces raisons, cdecl est un gagnant clair pour moi.

17voto

Brandon Moretz Points 4274

La plus grande différence dans les deux conventions d'appel, c'est que "__cdecl" met à la charge de l'équilibrage de la pile après un appel de fonction de l'appelant, ce qui permet pour les fonctions avec des quantités variables d'arguments. "__Stdcall" convention plus "simple" dans la nature, cependant moins souple à cet égard.

Aussi, je crois géré utilisation des langues convention stdcall par défaut, donc n'importe qui à l'aide de P/Invoke, il aurait explicitement état de la convention d'appel si vous allez avec cdecl.

Donc, si tous vos signatures de fonction vont être définis de manière statique je serais probablement pencher vers stdcall, si ce n'est cdecl.

9voto

user2471214 Points 62

En termes de sécurité, la convention __cdecl est "plus sûre" car c’est l’appelant qui doit désallouer la pile. Dans une bibliothèque __stdcall il peut arriver que le développeur ait oublié de désallouer correctement la pile ou qu'un attaquant puisse injecter du code en corrompant la pile de la DLL (par exemple, par un raccordement d'API), qui n'est alors pas vérifiée par l'appelant. Je n'ai aucun exemple de sécurité CVS montrant que mon intuition est correcte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X