Quelle est la signification et l'utilisation de stdcall?

je suis tombé sur __stdcall beaucoup ces jours-ci.

MSDN n'explique pas très clairement ce qu'il signifie vraiment, quand et pourquoi devrait-il être utilisé, si tant est qu'il le soit.

je vous saurais gré de bien vouloir fournir une explication, de préférence avec un ou deux exemples.

56
demandé sur Jean-François Fabre 2009-08-20 18:03:10

9 réponses

toutes les fonctions en C/C++ ont une convention d'appel particulière. Le but d'une convention d'appel est d'établir comment les données sont transmises entre l'appelant et le destinataire de l'appel et qui est responsable des opérations telles que le nettoyage de la pile d'appels.

les conventions d'appel les plus populaires sur windows sont

  • stdcall
  • cdecl
  • clrcall
  • fastcall
  • thiscall

ajouter ce spécificateur à la déclaration de la fonction indique essentiellement au compilateur que vous voulez que cette fonction particulière ait cette convention d'appel particulière.

les conventions d'appel sont documentées ici

Raymond Chen a également fait un long série sur l'histoire des diverses conventions d'appel (5 parties) commençant ici.

50
répondu JaredPar 2018-04-03 19:12:04

traditionnellement, les appels de fonction C sont faits avec l'appelant poussant certains paramètres sur la pile, appelant la fonction, et ensuite sautant la pile pour nettoyer ces arguments poussés.

/* example of __cdecl */
push arg1
push arg2
push arg3
call function
add sp,12 // effectively "pop; pop; pop"

Note: la convention par défaut - ci - dessus-est connue sous le nom de __cdecl.

l'autre convention la plus populaire est __stdcall. Dans les paramètres sont de nouveau poussé par l'appelant, mais la pile est nettoyé par le destinataire de l'appel. C'est la norme convention pour les fonctions API de Win32 (tel que défini par la macro WINAPI ), et il est aussi parfois appelé la convention d'appel "Pascal".

/* example of __stdcall */
push arg1 
push arg2 
push arg3 
call function // no stack cleanup - callee does this

cela ressemble à un détail technique mineur, mais s'il y a un désaccord sur la façon dont la pile est gérée entre l'appelant et le destinataire de l'appel, la pile sera détruite d'une manière qui est peu probable d'être récupéré. Puisque _ _ stdcall fait le nettoyage de la pile, le (très petit) code pour effectuer cette tâche se trouve à un seul endroit, plutôt que d'être dupliqué dans chaque appelant comme il est dans __cdecl. Cela rend le code très légèrement plus petit, bien que l'impact de la taille ne soit visible que dans les grands programmes.

les fonctions variadiques comme printf () sont presque impossibles à obtenir avec __stdcall, parce que seul l'appelant sait vraiment Combien d'arguments ont été passés afin de les nettoyer. L'appelant peut faire de bonnes suppositions (par exemple, en regardant une chaîne de format), mais le nettoyage de la pile devrait être déterminé par le la logique réelle de la fonction, pas le mécanisme de la Convention d'appel lui-même. Par conséquent, seul _ _ cdecl supporte les fonctions variadiques afin que l'appelant puisse faire le nettoyage.

Linker symbole nom décorations: Comme mentionné dans un point ci-dessus, appeler une fonction avec la "mauvaise" convention peut être désastreux, de sorte que Microsoft a un mécanisme pour éviter que cela ne se produise. Cela fonctionne bien, même si cela peut être exaspérant si l'on ne connaît pas les raisons. Ils ont choisi de résoudre ce problème en encodant la convention d'appel dans les noms de fonctions de bas niveau avec des caractères supplémentaires (qui sont souvent appelés "décorations"), et ceux-ci sont traités comme des noms sans rapport par le linker. La convention d'appel par défaut est __cdecl, mais chacune peut être demandée explicitement avec le /g? paramètre du compilateur.

_ _ cdecl (cl /GD ...)

tous les noms de fonctions de ce type sont précédés d'un trait de soulignement, et le nombre de paramètres cela n'a pas vraiment d'importance parce que l'appelant est responsable de la configuration et du nettoyage de la pile. Il est possible que l'appelant et l'appelant soient confondus sur le nombre de paramètres réellement passés, mais au moins la discipline de pile est maintenue correctement.

_ _ stdcall (cl /GZ ...)

ces noms de fonction sont précédés d'un trait de soulignement et ajoutés avec @ plus le nombre d'octets de paramètres passés. Par ce mécanisme, il n'est pas possible d'appeler un fonction avec le "mauvais" type de, ou même avec le mauvais nombre de paramètres.

_ _ fastcall (cl /Gr ...)

ces noms de fonction commencent par un signe @ et sont suffixés du nombre de paramètres@, un peu comme __stdcall.

exemples:

Declaration                        ----------------------->    decorated name


void __cdecl foo(void);            ----------------------->    _foo

void __cdecl foo(int a);           ----------------------->    _foo

void __cdecl foo(int a, int b);    ----------------------->    _foo

void __stdcall foo(void);          ----------------------->    _foo@0

void __stdcall foo(int a);         ----------------------->    _foo@4

void __stdcall foo(int a, int b);  ----------------------->    _foo@8

void __fastcall foo(void);         ----------------------->    @foo@0

void __fastcall foo(int a);        ----------------------->    @foo@4

void __fastcall foo(int a, int b); ----------------------->    @foo@8
43
répondu edge 2017-10-25 02:51:36

__stdcall est une convention d'appel: une façon de déterminer la façon dont les paramètres sont transmis à une fonction (sur la pile ou dans les registres) et qui est responsable du nettoyage après la fonction renvoie (l'appelant ou de l'appelé).

Raymond Chen a écrit un blog sur le major x86 appelant conventions , et il y a une belle article Codeprojet trop.

Pour la plupart, vous ne devriez pas avoir de soucis à propos d'eux. Le seul cas dans lequel vous devriez le faire est si vous appelez une fonction de bibliothèque qui utilise autre chose que la fonction par défaut -- sinon le compilateur générera le mauvais code et votre programme se plantera probablement.

7
répondu Nick Meyer 2009-08-20 14:08:53

malheureusement, il n'y a pas de réponse facile pour savoir quand l'utiliser ou non.

__stdcall signifie que les arguments d'une fonction sont poussés sur la pile de la première à la dernière. Ceci est à l'opposé de __cdecl, ce qui signifie que les arguments sont poussés du dernier au premier, et _ _ fastcall, qui place les quatre premiers arguments (je pense) dans les registres, et le reste va sur la pile.

vous avez juste besoin de savoir ce que la callee attend, ou si vous écrivez une bibliothèque, ce que vos appelants sont susceptibles d'attendre, et assurez-vous de documenter votre convention choisie.

6
répondu Jonathan 2009-08-20 14:08:00

il spécifie une convention d'appel pour une fonction. Une convention d'appel est un ensemble de règles sur la façon dont les paramètres sont passés à une fonction: dans quel ordre, par adresse ou par copie, qui doit nettoyer les paramètres (appelant ou appelé), etc.

3
répondu sbi 2009-08-20 14:07:28

__stdcall désigne une convention d'appel (voir PDF pour quelques détails). Cela signifie qu'il spécifie comment les arguments de fonction sont poussés et sautés de la pile, et qui est responsable.

_ _ stdcall est juste une des conventions d'appel, et est utilisé tout au long de la WINAPI. Vous devez l'utiliser si vous fournissez des pointeurs de fonction comme callbacks pour certaines de ces fonctions. En général, vous n'avez pas besoin d'indiquer d'appel convention dans votre code, mais il suffit d'utiliser la valeur par défaut du compilateur, sauf dans le cas mentionné ci-dessus (fournir des callbacks au code de tiers).

2
répondu gimpf 2009-08-20 14:09:29

C'est une convention d'appel que les fonctions WinAPI doivent être appelées correctement. Une convention d'appel est un ensemble de règles sur la façon dont les paramètres sont passés dans la fonction et comment la valeur de retour est passée de la fonction.

si l'appelant et le code appelé utilisent des conventions différentes, vous rencontrez un comportement non défini (comme un tel crash bizarre ).

les compilateurs C++ n'utilisent pas _ _ stdcall par défaut - ils utilisez d'autres conventions. Ainsi, pour appeler les fonctions WinAPI à partir de C++, vous devez spécifier qu'elles utilisent __stdcall - cela se fait généralement dans les fichiers D'en-tête Windoes SDK et vous le faites aussi lors de la déclaration des pointeurs de fonction.

1
répondu sharptooth 2017-05-23 12:34:47

simplement mis quand vous appelez la fonction, il est chargé dans la pile/registre. __stdcall est une convention / manière (argument de droite d'abord, puis argument de gauche ...), _ _ decl est une autre convention qui est utilisée pour charger la fonction sur la pile ou les registres.

si vous les utilisez, vous demandez à l'ordinateur d'utiliser cette façon spécifique de charger/décharger la fonction pendant la liaison et donc vous n'obtiendriez pas un décalage/plantage.

sinon la fonction-callee et fonction-appelant peut utiliser différentes conventions provoquant le programme de planter.

1
répondu dev ray 2011-11-30 10:07:51

__stdcall est la convention d'appel utilisée pour la fonction. Cela indique au compilateur les règles qui s'appliquent pour configurer la pile, pousser les arguments et obtenir une valeur de retour. Il y a un certain nombre d'autres conventions d'appel comme __cdecl , __thiscall , __fastcall et __nus .

__stdcall est l' convention d'appel standard pour les appels du système Win32.

plus de détails peuvent être trouvés sur Wikipedia .

1
répondu Anand 2017-12-07 06:16:47