Any compiler provides you with a way to specify what calling
convention you want from a list of calling conventions chosen by that
compiler (look for e.g. __cdecl).
<--
On most machines, there is only one reasonable way to pass
arguments when calling a function, and most compilers do not
need or have extensions to specify many different calling
conventions---they use the standard ``extern "language"''.
-->
well, if one excludes 32 bit Windows, where in practice 4 calling
conventions are commonly used:
cdecl; stdcall; fastcall; and thiscall (modified cdecl).
<--
By "most machines", I meant most types of machines. Windows is
a bit of an exception, although even here, it's only really an
exception when using VC++, who decided not to use the standard
mechanism. (cdecl and stdcall resolve to ``extern "C"'' and
``extern "Pascal"'', I think. And thiscall is an extension of
cdecl, only relevant for ``extern "C++"''. The language also
allows a compiler to define something like ``extern "Fast"'',
although why one would use a slow call when a fast one is
available is beyond me.)
-->
yeah.
most compilers I have seen have used the "__callconv" type keywords,
although granted my experience is mostly limited to Windows (where this
convention would likely be default as MS uses it), and Linux (where
generally there is only a single calling convention in use, hence no real
need to use it...).
this notation makes a little more sense IMO than the 'extern "lang" '
notation in many cases, as it allows defining the calling convention of
function pointers, ... which the former can't do effectively, however, the
'extern "lang" ' notation does have the usefulness that it can be applied to
an entire block of definitions, rather than having to be endlessly repeated
for each declaration.
hence:
void (__stdcall *foo)(int x, double y);
and:
extern "C"
{
...
}
in most cases, fastcall can be ignored (it is almost never
used for external linkage AFAICT), and thiscall can simply be
regarded as a special case of cdecl.
this is a major reason for modifier tags like WINAPI and
similar: they wrap the calling convention keywords.
on 64-bit Windows, there is a single calling convention (Win64);
on 64-bit Linux and OSX, there is a single calling convention (AMD64);
<--
As is the case under Solaris, HP/UX and AIX. And probably every
other system around.
-->
most non-Windows systems on x86-64 AFAIK use AMD64.
admittedly, I personally like Win64's design a little more, as AMD64 seems a
bit complicated and over-engineered and likely to actually reduce
performance slightly in common use cases vs Win64's design.
on 32-bit Linux, in practice pretty much everyone just uses
cdecl...
<--
On 32-bit Linux, I've never used anything.
-->
on 32-bit Linux, there is only a single calling convention in single use, so
no one needs to...
doesn't mean the calling convention is not there, only that it is not needed
to specify it.
IIRC, MS-DOS was a mess though, with many compilers doing
things differently, so code from one compiler would not
normally link correctly with code produced by another.
<--
Yes and no. All of the C compilers I tried did the same thing.
All of the C++ compilers were different. But that's the case
almost universally today as well.
-->
there were differences.
many C compilers used OMF (as the object format), and some used others
(including COFF, but this was typically for DPMI-based compilers, as well as
I think I remember there being 32-bit OMF, ...);
there were a few others as well IIRC.
although, all this was long ago, and my memory is faded.
32-bit Windows mostly stabilized the calling convention and
object-file format mess (nearly everything is either cdecl or
stdcall, and uses COFF...).
<--
Windows defines an ABI for C, I think (which it uses when
calling into system DLL's).
-->
well, or it can be said that there are 2 in common use:
stdcall (used for many DLL's) and cdecl (used for pretty much everything
else).
supporting both, one can interface with pretty much anything of relevance.
on many other systems, it is a single convention in use, but which it is
will vary from system to system (and the specifics will depend on the CPU
arch, ...).
but, Windows and x86 (or Windows and x64 / x86-64) represent the vast
majority of total systems (desktop and laptop at least) in use...
Linux and OSX (on x86 or x86-64) are most of the rest.
ARM and PPC are used in many embedded systems.
(not sure the OS popularity distribution for embedded systems, from what I
have seen I would guess: Linux, FreeDOS, and various proprietary OS's...).
most other architectures and operating systems can be largely safely
ignored...
in my case, I am still using the C calling conventions (for the specific
targets I support, mostly Windows and Linux), even for non-C languages (my
partial Java and C# implementation, as well as BGBScript, which is based on
ECMAScript).
granted, I do tend to use a modified ABI (I see the calling convention and
ABI as separate-but related, where an ABI may specify things not part of the
calling convention proper, and the calling convention is mostly responsible
for how data gets to/from the function on a given arch, but ignores
secondary issues such as function naming or sideband data).
yes, closures and similar are a bit of a hack (they use heap-allocated
"executable objects"), and there is no "good" way to handle full
continuations, so I largely ignore the latter (partial continuations can be
handled via a longjmp-like mechanism).
C level interop is possible then, but direct C++ level interop is not.
plugging between C++ and BGBScript would still require using 'extern "C" ',
and does not directly facilitate high-level types.
however, some level of interop is facilitated by dynamic code-generation
(mostly to try to patch together the BGBScript and C typesystems, where one
supports dynamic typing, and the other is primarily statically-typed...).
note: apart from some amount of either link-time or run-time generated code,
my ABI wouldn't work...
the ABI was largely originally designed to deal with dynamically-generated
code (though some information is redundant, as I originally designed it
before moving to using a database-like structure for code patching, so the
ABI had to be largely self-defining, rather than being able to rely on
external metadata queries to resolve many issues).
I had considered some possibility of using other (more specialized) calling
conventions, but decided against this due to the overall costs (for example,
a calling convention capable of pulling off full continuations would
necessarily have problems with C-level interop, and I know of know good way
to support full continuations in C apart from ugly stack-jumping hackery,
which is preferably avoided...).
static linking of C or C++ against BGBScript (or later C# or Java) also
currently doesn't work, as there is no real "good" way to handle late
binding in statically-compiled code (this means it is needed to fetch and
call through function pointers...).
dynamically-compiled C doesn't have this issue though (but has its own share
of issues, mostly the plague of compiler bugs...).
and so on...