Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

stdcall and cdecl

Tags:

c++

stdcall

cdecl

There are (among others) two types of calling conventions - stdcall and cdecl. I have few questions on them:

  1. When a cdecl function is called, how does a caller know if it should free up the stack ? At the call site, does the caller know if the function being called is a cdecl or a stdcall function ? How does it work ? How does the caller know if it should free up the stack or not ? Or is it the linkers responsibility ?
  2. If a function which is declared as stdcall calls a function(which has a calling convention as cdecl), or the other way round, would this be inappropriate ?
  3. In general, can we say that which call will be faster - cdecl or stdcall ?
like image 790
Rakesh Agarwal Avatar asked Aug 04 '10 09:08

Rakesh Agarwal


People also ask

What is difference between Cdecl and Stdcall?

__cdecl is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code.

What does __ Stdcall mean?

The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl . Functions that use this calling convention require a function prototype. The __stdcall modifier is Microsoft-specific.

What does Cdecl stand for?

The cdecl (C Declaration) calling convention is usually the default calling convention for x86 C compilers.

How does the Stdcall calling convention work?

The stdcall calling convention is a variation on the Pascal calling convention in which the callee is responsible for cleaning up the stack, but the parameters are pushed onto the stack in right-to-left order, as in the _cdecl calling convention. Registers EAX, ECX, and EDX are designated for use within the function.


2 Answers

Raymond Chen gives a nice overview of what __stdcall and __cdecl does.

(1) The caller "knows" to clean up the stack after calling a function because the compiler knows the calling convention of that function and generates the necessary code.

void __stdcall StdcallFunc() {}  void __cdecl CdeclFunc() {     // The compiler knows that StdcallFunc() uses the __stdcall     // convention at this point, so it generates the proper binary     // for stack cleanup.     StdcallFunc(); } 

It is possible to mismatch the calling convention, like this:

LRESULT MyWndProc(HWND hwnd, UINT msg,     WPARAM wParam, LPARAM lParam); // ... // Compiler usually complains but there's this cast here... windowClass.lpfnWndProc = reinterpret_cast<WNDPROC>(&MyWndProc); 

So many code samples get this wrong it's not even funny. It's supposed to be like this:

// CALLBACK is #define'd as __stdcall LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg     WPARAM wParam, LPARAM lParam); // ... windowClass.lpfnWndProc = &MyWndProc; 

However, assuming the programmer doesn't ignore compiler errors, the compiler will generate the code needed to clean up the stack properly since it'll know the calling conventions of the functions involved.

(2) Both ways should work. In fact, this happens quite frequently at least in code that interacts with the Windows API, because __cdecl is the default for C and C++ programs according to the Visual C++ compiler and the WinAPI functions use the __stdcall convention.

(3) There should be no real performance difference between the two.

like image 178
In silico Avatar answered Sep 20 '22 17:09

In silico


In CDECL arguments are pushed onto the stack in revers order, the caller clears the stack and result is returned via processor registry (later I will call it "register A"). In STDCALL there is one difference, the caller doeasn't clear the stack, the calle do.

You are asking which one is faster. No one. You should use native calling convention as long as you can. Change convention only if there is no way out, when using external libraries that requires certain convention to be used.

Besides, there are other conventions that compiler may choose as default one i.e. Visual C++ compiler uses FASTCALL which is theoretically faster because of more extensive usage of processor registers.

Usually you must give a proper calling convention signature to callback functions passed to some external library i.e. callback to qsort from C library must be CDECL (if the compiler by default uses other convention then we must mark the callback as CDECL) or various WinAPI callbacks must be STDCALL (whole WinAPI is STDCALL).

Other usual case may be when you are storing pointers to some external functions i.e. to create a pointer to WinAPI function its type definition must be marked with STDCALL.

And below is an example showing how does the compiler do it:

/* 1. calling function in C++ */ i = Function(x, y, z);  /* 2. function body in C++ */ int Function(int a, int b, int c) { return a + b + c; }

CDECL:

/* 1. calling CDECL 'Function' in pseudo-assembler (similar to what the compiler outputs) */ push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x' call (jump to function body, after function is finished it will jump back here, the address where to jump back is in registers) move contents of register A to 'i' variable pop all from the stack that we have pushed (copy of x, y and z)  /* 2. CDECL 'Function' body in pseudo-assembler */ /* Now copies of 'a', 'b' and 'c' variables are pushed onto the stack */ copy 'a' (from stack) to register A copy 'b' (from stack) to register B add A and B, store result in A copy 'c' (from stack) to register B add A and B, store result in A jump back to caller code (a, b and c still on the stack, the result is in register A)

STDCALL:

/* 1. calling STDCALL in pseudo-assembler (similar to what the compiler outputs) */ push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x' call move contents of register A to 'i' variable  /* 2. STDCALL 'Function' body in pseaudo-assembler */ pop 'a' from stack to register A pop 'b' from stack to register B add A and B, store result in A pop 'c' from stack to register B add A and B, store result in A jump back to caller code (a, b and c are no more on the stack, result in register A)
like image 22
adf88 Avatar answered Sep 21 '22 17:09

adf88