Prabhu R
Prabhu R

Reputation: 14222

What are the different calling conventions in C/C++ and what do each mean?

There are different calling conventions available in C/C++: stdcall, extern, pascal, etc. How many such calling conventions are available, and what do each mean? Are there any links that describe these?

Upvotes: 37

Views: 32442

Answers (6)

Davislor
Davislor

Reputation: 15134

They’re platform-specific extensions needed to call functions in certain libraries, particularly the Win32 API. They’re nonstandard and specific to each compiler, although MSVC’s options are the de facto standard for Windows on x86. Normally, a library that needs them will declare them in the header files and they will work transparently. The main difference between them is that C historically used a less-efficient convention that allowed for a variable number of arguments of any type, while Windows and most other languages did it differently. A lot of the differences, though, such as pushing left-handed or right-handed and having the caller or the called function clean up, were pretty arbitrary.

They’re largely irrelevant to 64-bit code: the holy wars over calling conventions never happened on those platforms.

There are a few common cases where you might need to add one of these to a function. A C++ module that needs to link with modules written in other languages (and sometimes even other C++ compilers) will have to use the extern "C" naming convention for compatibility. A callback function needs to use the same calling convention as the caller, which with the Windows API is CALLBACK, not the default. A shared library might need to export its functions with a different calling convention than it uses internally, or might want to make its use of __cdecl explicit in case the default changes. You might or might not get better performance from __fastcall on some platforms: it mostly speeds up short leaf functions with one or two parameters, and could make some programs slower.

Upvotes: 2

Russell Hankins
Russell Hankins

Reputation: 1176

Simple answer: I use cdecl, stdcall, and fastcall. I seldom use fastcall. stdcall is used to call Windows API functions.

Detailed answer (Stolen from Wikipedia):

cdecl - In cdecl, subroutine arguments are passed on the stack. Integer values and memory addresses are returned in the EAX register, floating point values in the ST0 x87 register. Registers EAX, ECX, and EDX are caller-saved, and the rest are callee-saved. The x87 floating point registers ST0 to ST7 must be empty (popped or freed) when calling a new function, and ST1 to ST7 must be empty on exiting a function. ST0 must also be empty when not used for returning a value.

syscall - This is similar to cdecl in that arguments are pushed right-to-left. EAX, ECX, and EDX are not preserved. The size of the parameter list in doublewords is passed in AL.

pascal - the parameters are pushed on the stack in left-to-right order (opposite of cdecl), and the callee is responsible for balancing the stack before return.

stdcall - The stdcall[4] 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. Return values are stored in the EAX register.

fastcall - __fastcall convention (aka __msfastcall) passes the first two arguments (evaluated left to right) that fit into ECX and EDX. Remaining arguments are pushed onto the stack from right to left.

vectorcall - In Visual Studio 2013, Microsoft introduced the __vectorcall calling convention in response to efficiency concerns from game, graphic, video/audio, and codec developers.[7] For IA-32 and x64 code, __vectorcall is similar to __fastcall and the original x64 calling conventions respectively, but extends them to support passing vector arguments using SIMD registers. For x64, when any of the first six arguments are vector types (float, double, __m128, __m256, etc.), they are passed in via the corresponding XMM/YMM registers. Similarly for IA-32, up to six XMM/YMM registers are allocated sequentially for vector type arguments from left to right regardless of position. Additionally, __vectorcall adds support for passing homogeneous vector aggregate (HVA) values, which are composite types consisting solely of up to four identical vector types, using the same six registers. Once the registers have been allocated for vector type arguments, the unused registers are allocated to HVA arguments from left to right regardless of position. Resulting vector type and HVA values are returned using the first four XMM/YMM registers.

safecall - n Delphi and Free Pascal on Microsoft Windows, the safecall calling convention encapsulates COM (Component Object Model) error handling, thus exceptions aren't leaked out to the caller, but are reported in the HRESULT return value, as required by COM/OLE. When calling a safecall function from Delphi code, Delphi also automatically checks the returned HRESULT and raises an exception if necessary.

The safecall calling convention is the same as the stdcall calling convention, except that exceptions are passed back to the caller in EAX as a HResult (instead of in FS:[0]), while the function result is passed by reference on the stack as though it were a final "out" parameter. When calling a Delphi function from Delphi this calling convention will appear just like any other calling convention, because although exceptions are passed back in EAX, they are automatically converted back to proper exceptions by the caller. When using COM objects created in other languages, the HResults will be automatically raised as exceptions, and the result for Get functions is in the result rather than a parameter. When creating COM objects in Delphi with safecall, there is no need to worry about HResults, as exceptions can be raised as normal but will be seen as HResults in other languages.

Microsoft X64 Calling Convention - The Microsoft x64 calling convention[12][13] is followed on Windows and pre-boot UEFI (for long mode on x86-64). It uses registers RCX, RDX, R8, R9 for the first four integer or pointer arguments (in that order), and XMM0, XMM1, XMM2, XMM3 are used for floating point arguments. Additional arguments are pushed onto the stack (right to left). Integer return values (similar to x86) are returned in RAX if 64 bits or less. Floating point return values are returned in XMM0. Parameters less than 64 bits long are not zero extended; the high bits are not zeroed.

When compiling for the x64 architecture in a Windows context (whether using Microsoft or non-Microsoft tools), there is only one calling convention – the one described here, so that stdcall, thiscall, cdecl, fastcall, etc., are now all one and the same.

In the Microsoft x64 calling convention, it is the caller's responsibility to allocate 32 bytes of "shadow space" on the stack right before calling the function (regardless of the actual number of parameters used), and to pop the stack after the call. The shadow space is used to spill RCX, RDX, R8, and R9,[14] but must be made available to all functions, even those with fewer than four parameters.

The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile (caller-saved).[15]

The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile (callee-saved).[15]

For example, a function taking 5 integer arguments will take the first to fourth in registers, and the fifth will be pushed on the top of the shadow space. So when the called function is entered, the stack will be composed of (in ascending order) the return address, followed by the shadow space (32 bytes) followed by the fifth parameter.

In x86-64, Visual Studio 2008 stores floating point numbers in XMM6 and XMM7 (as well as XMM8 through XMM15); consequently, for x86-64, user-written assembly language routines must preserve XMM6 and XMM7 (as compared to x86 wherein user-written assembly language routines did not need to preserve XMM6 and XMM7). In other words, user-written assembly language routines must be updated to save/restore XMM6 and XMM7 before/after the function when being ported from x86 to x86-64.

Upvotes: 33

Mandrake
Mandrake

Reputation: 361

fastcall is the optimized one but nobody uses it

Upvotes: -3

MSalters
MSalters

Reputation: 179779

Standard C++ basically has two: extern "C" and extern "C++". The latter is the default; this former used when you need to link to C code. Compilers may define other strings besides "C" and "C++". For instance, a compiler that's compatible with its Pascal sibling may define extern "Pascal".

Unfortunately, some compilers have invented keywords instead. In these cases, see the compiler documentation.

Upvotes: 6

These concern what order to put parameters on the call stack, and when to use call by value and/or call by reference semantics. They are compiler specific extensions intended to simplify multilingual programming.

Upvotes: 3

anon
anon

Reputation:

Neither Standard C nor Standard C++ has such a concept - these are features of specific compilers, linkers and/or operating systems, so you should really indicate which specific technologies you are interested in.

Upvotes: 24

Related Questions