As I know, the calling convention is compiler and architecture dependent. But are there any clear differences between C and C++ calling conventions?
There are three major calling conventions that are used with the C language on 32-bit x86 processors: STDCALL, CDECL, and FASTCALL. In addition, there is another calling convention typically used with C++: THISCALL. There are other calling conventions as well, including PASCAL and FORTRAN conventions, among others.
There are different calling conventions available in C/C++: stdcall , extern , pascal , etc.
A calling convention is a scheme for how functions receive parameters from their caller and how they return a result. The calling conventions can differ in where parameters and return values are placed (in registers; on the call stack; a mix of both), the order they are placed.
thiscall. This calling convention is used for calling C++ non-static member functions. There are two primary versions of thiscall used depending on the compiler and whether or not the function uses a variable number of arguments.
There is nothing in either standard that requires the C and C++ calling conventions to be the same on a given compiler, other than that a C++ function declared extern "C"
necessarily must be called with the same calling convention as a C function.
That's why a pointer-to-function and a pointer-to-function-with-C-linkage with the same parameters and return type, have different types. When the function is called, the compiler can know from the type which calling convention to call it with, if they are different.
In practice, I don't think I've ever knowingly dealt with an example that uses an incompatible calling convention between free functions with and without C linkage. Usually a C++ implementation adopts its calling convention from the ABI of the system that it's planning to run on, so as to produce linkable objects (executables and libraries) that other users of the system can understand in terms of the ABI.
This isn't required -- the standard doesn't care whether or not there is a system ABI, and the system doesn't usually care how calls are made within a self-contained executable[*]. It's just sensible to do it unless there's some extraordinary reason not to. The system ABI on a given system may or may not mention C++ -- if not then the C++ implementation is on its own as far as non-C-linkage functions are concerned, but as I say it is usually sensible to make functions that could have C linkage use the same calling convention as if they do have C linkage.
I say "incompatible" rather than "different", because of course there are some things that aren't mentioned in the C calling convention but need to be specified in the C++ calling convention. How to pass a pointer-to-member-function, for example. It may well be that this is not pinned down by the system ABI, and so is left to the C++ implementation. The reason for this is to leave the implementation of pointer-to-member-function up to the C++ implementation, rather than the system ABI doing something that the manufacturer considers to be the job of a C++ compiler writer.
With the calling convention out of the way, note that name mangling inevitably is different between a free function with or without C linkage. The reason is that C++ name mangling must include the types of the parameters (because of function overloading), whereas C name mangling must not (because of extern function declarations with unspecified parameters).
[*] Although I've seen examples where using the "wrong" calling convention does break things. ISTR a Windows mobile device where if you formatted the stack differently from what the OS expected, then certain hardware exceptions would take out the device because the OS tried to retrace the stack of the offending thread, and couldn't. So at least on that OS version, probably around 2005, if you wanted the OS's diagnostics to work then you had to use the Windows calling conventions internally. Or anyway the part of the calling convention relating to stack frame format. This was entirely our screwup, of course, but I don't know whether we could have fixed it properly by installing our own handlers for the hardware exceptions, rather than working around them by not causing the exceptions in the first place. It did mean that a user-mode process could trivially take the OS down with a stack overrun, though, and also that it was harder to debug our code than on other Windowses. So we slightly blamed the OS.
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