__cdecl
calling convention says that:caller cleanup stack.
__stdcall
calling convention says that: callee cleanup stack.
So i try to test code below:
#include <...>
char *callee()
{
char str[] = "abcd";
return str;
}
int main()
{
char *str;
str = callee();
printf("%s\n", str);
return 0;
}
According to the two calling convention above, I think:
__cdecl
stack cleanup by caller, so printf("%s\n", str)
should output "abcd".
__stdcall
stack cleanup by callee, so printf("%s\n", str)
should output messy chars.
But in fact, two all output messy chars. I am confused. Thanks for help!
"Clean up the stack" actually means "adjust the stack pointer so that it matches the changes done to stack pointer when arguments and return address were pushed onto stack". In your example it would be irrelevant who cleans up the stack - you would get the same undefined behavior, because you try to access a stack-allocated variable that is overwritten by a series of later pushes of arguments needed to perform printf()
.
If you only write code in C or C++ you should not care of the exact details like "who cleans up the stack" - those details are critical only when writing in assembly. In C and C++ just be sure to mark function pointers with right calling conventions before calling a function through those pointers and the compiler will do the rest.
Your error has no relation to calling convention. callee()
is returning a pointer to a local variable, which is invalid as soon as callee()
returns, and you get garbage data.
It doesn't work the way you thought, because in both cases the stack pointer is adjusted between each function call. The difference is just who does it.
With the __stdcall convention, the stack pointer is adjusted (removing all parameters) just before the function returns to the caller. This saves code, as it is only done in one place.
With the __cdecl convention, the stack pointer is adjusted by the calling code, just after the return from the called function. If you have functions with a variable number of parameters, like printf, it is hard for it to remove the parameters as there can be a different number for each point of gtcall. Therefore, the calling function will have to do the adjustment. It will know how many parameters were actually passed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With