What is the meaning and usage of __stdcall?
All functions in C/C++ have a particular calling convention. The point of a calling convention is to establish how data is passed between the caller and callee and who is responsible for operations such as cleaning out the call stack.
The most popular calling conventions on windows are
__stdcall
, Pushes parameters on the stack, in reverse order (right to left)__cdecl
, Pushes parameters on the stack, in reverse order (right to left)__clrcall
, Load parameters onto CLR expression stack in order (left to right).__fastcall
, Stored in registers, then pushed on stack__thiscall
, Pushed on stack; this pointer stored in ECX
Adding this specifier to the function declaration essentially tells the compiler that you want this particular function to have this particular calling convention.
The calling conventions are documented here
- https://learn.microsoft.com/en-us/cpp/cpp/calling-conventions
Raymond Chen also did a long series on the history of the various calling conventions (5 parts) starting here.
- https://devblogs.microsoft.com/oldnewthing/20040102-00/?p=41213
What is __stdcall?
__stdcall
is the calling convention used for the function. This tells the compiler the rules that apply for setting up the stack, pushing arguments and getting a return value.
There are a number of other calling conventions, __cdecl
, __thiscall
, __fastcall
and the wonderfully named __declspec(naked)
. __stdcall
is the standard calling convention for Win32 system calls.
Wikipedia covers the details.
It primarily matters when you are calling a function outside of your code (e.g. an OS API) or the OS is calling you (as is the case here with WinMain). If the compiler doesn't know the correct calling convention then you will likely get very strange crashes as the stack will not be managed correctly.
What is advantage/use of __stdcall?
opcua_client::onShutdownMessage
looks like callback function. That is, a function that is sent to some API which calls the function at a later time. The callback function must then have the calling convention expected by the API, in this case __stdcall
. Since __stdcall
is the default calling convention on the Win32 platform, it does not have to be specified when building for Win32.
Plainly and simply, why do we use _stdcall?
The reason for having some calling convention is pretty simple: so that the caller and the callee agree on how things will work. Without it, the caller doesn't know where to put arguments when it's calling a particular function.
As for why Microsoft decided on the specific details of _stdcall
, that's largely historical. On MS-DOS, all calls were register based, so all OS calls required assembly language, or strange extensions to most higher-level languages.
When they first did Windows, they used the cdecl
calling convention, mostly because that's what the compiler did by default. At least according to rumor, shortly before they got ready to release Windows 1.0, they switched to the Pascal calling convention because it was enough more efficient that (among other things) it allowed Windows to fit on one fewer floppy disc. Regardless of the precise details, the Pascal calling convention did make code a little smaller, because the called function cleaned up the arguments from the stack instead of needing to clean them up everywhere the function was called. For any function that was called from at least 2 different places, that's a win (and if it's tie anywhere else).
Then they started work on OS/2, and invented yet another calling convention (syscall).
Then, of course, came Win32. There wasn't really a lot wrong with syscall from a technical viewpoint, but (I'd guess) everything associated with OS/2 was considered tainted, so syscall had to go. The result was something just enough different to justify a new name. In fairness, that's a little bit of an exaggeration: they did add one truly useful addition: they encoded the number of bytes of arguments into each function name, so if (for example) you supplied an incorrect prototype for a function, the code wouldn't link rather than ending up with a mismatch between caller and callee that could lead to much more serious problems.
For the most part, it really comes back to the original point though: the exact details of the calling convention don't matter all that much, as long as you don't make a complete mess of it. Most of what matters is that the caller and callee agree on the same thing, so if a compiler knows what parameters a function accepts, it knows how to generate code to get those parameters to the function correctly (and, likewise, they both agree on how stack cleanup is handled, etc.)
Why use __stdcall for function pointer
Embedding a calling convention specifier in a function pointer allows you to use that calling convention when calling functions through that pointer. __stdcall is the calling convention used to call Win32 API functions.
The benefit of specifying it in a function pointer is being able to match a different calling convention according to your code's needs (e.g. when loading an external library's function via late binding). Library headers should specify them as a good programming practice.
There's a caveat though: if you embed a wrong calling convention in a function pointer, the compiler might be powerless to help you detect that and you might end up doing bad things at runtime.
Is there STDCALL in Linux?
The simplest solution is to just define __stdcall to nothing conditionally on Linux.
When using PInvoke, why use __stdcall?
There is only one calling convention on x64 and so it does not matter which calling convention you specify. It is always ignored on x64.
On x86 it is important to make sure calling conventions match on both sides of the interface. So if you ever anticipate running your code on x86 it would be prudent to get that right now.
Does every function in a Windows GUI application need to use stdcall?
WinMain is declared with
__stdcall
and calls all the functions I've defined. Does this mean all the functions I define should use thestdcall
calling convention?
No. Calling conventions are handled on a per-function-call basis, right at the call site. The convention dictates how the caller and callee manage the call stack - how parameters are passed, in what order, who cleans up the stack, etc. As long as the caller and callee agree to use the same calling convention on each individual function call, it is perfectly safe for a stdcall
function to call a function that uses a different convention, like cdecl
, and vice versa. A function's calling convention applies only when:
- the function is being entered by a new caller.
- the function is returning back to that caller.
- the function is accessing its own parameters.
Outside of that, what a function does internally has nothing to with its own calling convention.
For example, lets say that WinMain()
, a stdcall
function, wants to call a cdecl
function.
It does not matter at all that WinMain()
is itself a stdcall
function. While code execution is inside of WinMain()
, it can do whatever it wants. WinMain()
's stdcall
convention is applied only upon entry and exit of WinMain()
itself. That is the contract WinMain()
has with ITS caller.
What matters is that WinMain()
must follow the rules of cdecl
when setting up the call stack for a cdecl
function that it is about to call into, and cleaning up the call stack when that function returns back to WinMain()
.
The same goes for any function call of any calling convention.
I've tried not using
__stdcall
and nothing bad happened. I have also seen well-known GUI libraries supporting Windows don't usestdcall
. Why is the stack not corrupting?
Because the call stack is being managed correctly at every function call and return, so there is no unbalanced cleanup to corrupt the stack.
Related Topics
Why Is This Cin Reading Jammed
Difference Between a Virtual Function and a Pure Virtual Function
Explain C++ Sfinae to a Non-C++ Programmer
Is There a Good Python Library That Can Parse C++
How to Link to Dynamic Boost Libs
What Makes a Static Variable Initialize Only Once
Why Does Same_As Concept Check Type Equality Twice
C++: Is It Safe to Cast Pointer to Int and Later Back to Pointer Again
Argument of Type "Char *" Is Incompatible with Parameter of Type "Lpwstr"
Is It a Good Idea to Wrap an #Include in a Namespace Block
How to Scale Down Numbers from Rand()
Tmp: How to Generalize a Cartesian Product of Vectors