C/C++ calling convention

  • Thread starter StanisÅ‚aw Findeisen
  • Start date
I

Ian Collins

Given an architecture and a language (C or C++), is there any standard
function calling convention? Or is it compiler dependent?

The two languages are different. With C, there will be a platform
standard, with C++ it is still (regrettably) compiler specific.
 
B

BGB / cr88192

Ian Collins said:
The two languages are different. With C, there will be a platform
standard, with C++ it is still (regrettably) compiler specific.

yep...

however, typically, C++ uses the same basic calling convention as C, but
usually differing only in that the C++ case tends to use a name-mangling
scheme (often compiler specific, but some "de-facto" conventions exist, for
example the use of MSVC-like conventions on Windows and the IA-64 ABI
name-mangling on Linux).

there does tend to be a difference in how compilers pass 'this', with some
compilers using an additional register (thiscall in MSVC), but more commonly
it is passed as a hidden first argument (although AFAIK usually after the
hidden first argument used for returning structs).


although, it is not really "safe" to rely on the specifics of any of this...

similarly, it is not really "safe" to use C++-based APIs across library
boundaries, nor for that matter to pass memory or file references between
DLL's (this leads to "fun" sometimes...).

for example, MSVC likes giving each DLL its own local C library, and hence,
its own local memory heap and set of open files, resulting in a few issues
which may pop up occassionally... (these issues don't tend to pop up with
MinGW or Cygwin, as these handle this situation differently...).

or such...
 
I

Ian Collins

however, typically, C++ uses the same basic calling convention as C, but
usually differing only in that the C++ case tends to use a name-mangling
scheme (often compiler specific, but some "de-facto" conventions exist, for
example the use of MSVC-like conventions on Windows and the IA-64 ABI
name-mangling on Linux).

there does tend to be a difference in how compilers pass 'this', with some
compilers using an additional register (thiscall in MSVC), but more commonly
it is passed as a hidden first argument (although AFAIK usually after the
hidden first argument used for returning structs).


although, it is not really "safe" to rely on the specifics of any of this...

similarly, it is not really "safe" to use C++-based APIs across library
boundaries, nor for that matter to pass memory or file references between
DLL's (this leads to "fun" sometimes...).

That is very platform specific. Those restrictions don't apply to Unix
or Unix like systems.
 
B

BGB / cr88192

Ian Collins said:
That is very platform specific. Those restrictions don't apply to Unix or
Unix like systems.

yes, but code which works on both sets of systems may need to abide by these
seemingly arbitrary restrictions as well...


like, for example, I recently had to do a bit of "creative tweaking" to be
able to get one of Xiph.org's codecs (Tremor, which is a minimalist
OGG/Vorbis decoder) to build and work on Windows.

it was funny, the code touted about how pure ANSI C and portable it was, yet
I still encountered several instances of:
minor compiler extensions (things which could have easily been overlooked,
such as doing arithmetic on void pointers, ...);
it using autoconf, which is itself non-portable;
some C99 features, and using a header which doesn't exist on Windows
("sys/time.h"), ...

as well as me tearing out the autoconf (I tend to use Makefiles for
damn-near everything, personally finding this to work better in my case),
....

as well as adding in some stuff to allow it to work as a DLL, ...


so, yes, portability is relative...

one can write much code which works nearly everywhere else, but doesn't work
on Windows, and one can easily write code on Windows which doesn't work
anywhere else...


much the same as code which hemorages memory can't be expected to work well
on many embedded systems either (what?... this thing only has 64MB of RAM
and no swap?...).
 
G

Goran Pusic

Given an architecture and a language (C or C++), is there any standard
function calling convention? Or is it compiler dependent?

As far as I know, and as far as the language is concerned, calling
convention is absolutely 100% compiler and underlying CPU architecture
dependent^^^. (Is there some standard-dratft-dwelling-newsgroupie to
refute/confirm this?). If you look at e.g. C99 standard draft (and I
doubt it's different for previous versions), you will find no
mentioning of "calling convention", no "cdecl" or whatever, no
nothing.

Goran.
 
S

Stanisław Findeisen

yep...

however, typically, C++ uses the same basic calling convention as C, but
usually differing only in that the C++ case tends to use a name-mangling
scheme (often compiler specific, but some "de-facto" conventions exist, for
example the use of MSVC-like conventions on Windows and the IA-64 ABI
name-mangling on Linux).

there does tend to be a difference in how compilers pass 'this', with some
compilers using an additional register (thiscall in MSVC), but more commonly
it is passed as a hidden first argument (although AFAIK usually after the
hidden first argument used for returning structs).

What exactly happens when you compile your C++ function with extern "C"
declaration? Is it compiled and linked as if it was a C function?

What if such a function throws an exception?

What calling convention is used when that function is being called from
C++ code (from the same, or another translation unit)?

What calling convention is used when that function calls some other
function (be it C, C++ or C++ with extern "C" declaration)? What if that
other function throws an exception?

I am mixing some C with C++, and would like the code to be portable.
However I only care about POSIX and GNU/Linux.

STF

http://eisenbits.homelinux.net/~stf/
OpenPGP: DFD9 0146 3794 9CF6 17EA D63F DBF5 8AA8 3B31 FE8A
 
I

Ian Collins

What exactly happens when you compile your C++ function with extern "C"
declaration? Is it compiled and linked as if it was a C function?

Not compiled (it is still C++), but it will have the same linkage as C
functions on the same platform.
What if such a function throws an exception?

All bets are off.
What calling convention is used when that function is being called from
C++ code (from the same, or another translation unit)?

C++ will call it as it would any other C function.
What calling convention is used when that function calls some other
function (be it C, C++ or C++ with extern "C" declaration)? What if that
other function throws an exception?

extern "C" has no effect here.
 
G

Goran Pusic

What exactly happens when you compile your C++ function with extern "C"
declaration? Is it compiled and linked as if it was a C function?

I'd say that for a given compiler (version) on a given platform,
there's no difference between a C and a C++ function, except that you
need extern "C" to turn off name mangling that happens with a C++
compiler. So that's why you have extern "C".
What if such a function throws an exception?

You have a bug, one of invoking undefined behavior? You see, if a
function is a C one, idea is that you want to interface with C, who
knows not of exceptions.
What calling convention is used when that function is being called from
C++ code (from the same, or another translation unit)?

Should be OK (given correct exception safety, which you should not
care about since function is a "C" one, and C code can't throw; IOW,
don't do silly things).
What calling convention is used when that function calls some other
function (be it C, C++ or C++ with extern "C" declaration)? What if that
other function throws an exception?

Apply transitivity here :)
I am mixing some C with C++, and would like the code to be portable.
However I only care about POSIX and GNU/Linux.

If you are calling C from C++, you're fine. If vice-versa, wrap any
extern "C" C++ functions into a try/catch and convert exception into
an error-return. Easy.

However, "portability" is a big word when speaking about C and C++
languages :). Practical advice: you won't get it until you compile
with several compilers/versions, for several hardware architectures
and underlying OS-es. Also, you will fail for considerations other
than what you have up until now ;-).

Goran.
 
J

James Kanze

On 08/25/10 08:56 AM, Stanisław Findeisen wrote:
The two languages are different. With C, there will be
a platform standard, with C++ it is still (regrettably)
compiler specific.

Maybe. Formally, the situation is the same for both languages;
the language standard doesn't address this issue, it is up to
the platforms. Practically, there are very few platforms which
don't have a standard function calling convention for C, and not
too many which have one for C++ (but I think Linux has one, and
Itanium based machines).

In practice, when writing C++, just having common calling
conventions isn't enough. You need compatible implementations
of the STL as well. And on many implementations (g++, VC++),
the actual implementation of the STL changes depending on
compiler options, and even compiling all of the code with the
same compiler is no guarantee---you have to be sure that all of
the significant options were the same as well.
 
J

James Kanze

however, typically, C++ uses the same basic calling convention as C, but
usually differing only in that the C++ case tends to use a name-mangling
scheme (often compiler specific, but some "de-facto" conventions exist, for
example the use of MSVC-like conventions on Windows and the IA-64 ABI
name-mangling on Linux).

How can it? Things like the layout of the vtable are part of
the calling conventions, and C++ can't possibly use the same
ones as C here.
there does tend to be a difference in how compilers pass
'this', with some compilers using an additional register
(thiscall in MSVC), but more commonly it is passed as a hidden
first argument (although AFAIK usually after the hidden first
argument used for returning structs).

Except on Intel, the first argument *is* usually in a register.
although, it is not really "safe" to rely on the specifics of
any of this...
similarly, it is not really "safe" to use C++-based APIs
across library boundaries, nor for that matter to pass memory
or file references between DLL's (this leads to "fun"
sometimes...).

That's not true, and I've done it on many platforms.
for example, MSVC likes giving each DLL its own local C library,

MSVC does what you tell it in this regard. If you tell it to
give each DLL its own local C library, when you don't want to,
it's nobody's fault but your own.
and hence, its own local memory heap and set of open files,
resulting in a few issues which may pop up occassionally...
(these issues don't tend to pop up with MinGW or Cygwin, as
these handle this situation differently...).

I don't know about MinGW or Cygwin, but under most Unix, it's
also possible to arrange things so that each shared object has
its own free space arena as well, if this is what you want.
 
J

James Kanze

On 08/25/10 02:50 PM, BGB / cr88192 wrote:

[...]
That is very platform specific. Those restrictions don't
apply to Unix or Unix like systems.

Which part of his statement are you referring to? It's not safe
to use C++ based APIs (with std::string, etc.) between code
compiled with different compiler options, with the same
compiler. And there's no problem passing memory or file
references between dynamically loaded object files on any of the
systems I've worked on, Windows or Unix. (We do it all the time
under Windows, here, and we did it regularly under Solaris and
Linux where I was before.)
 
J

James Kanze

On Aug 25, 9:42 am, Stanis³aw Findeisen <[email protected]> wrote:

[...]
I'd say that for a given compiler (version) on a given platform,
there's no difference between a C and a C++ function, except that you
need extern "C" to turn off name mangling that happens with a C++
compiler. So that's why you have extern "C".

And you'd be wrong. At least one compiler I've used used
different calling conventions for C and for C++.
 
G

Goran Pusic

On Aug 25, 9:42 am, Stanis³aw Findeisen <[email protected]> wrote:

    [...]
I'd say that for a given compiler (version) on a given platform,
there's no difference between a C and a C++ function, except that you
need extern "C" to turn off name mangling that happens with a C++
compiler. So that's why you have extern "C".

And you'd be wrong.  At least one compiler I've used used
different calling conventions for C and for C++.

Ugh. Which one and why (if you can be bothered)?

To be honest, I can't think of a reason why would any compiler match
calling conventions betwen C and C++, but that seems a most reasonable
(only sensible, really) thing to do when using extern "C".

Goran.
 
S

Stanisław Findeisen

Not compiled (it is still C++), but it will have the same linkage as C
functions on the same platform.

But calling convention is part of the function machine code, isn't it?
So I guess this is generated in compilation phase...
All bets are off.


C++ will call it as it would any other C function.


extern "C" has no effect here.

So if the function in question (the one in C++, with extern "C")
receives a function pointer, and calls it, it will be called in C++
convention (the current one for the compiler+architecture)?... :-O

How to make it call this anonymous function pointer in C convention?

STF

http://eisenbits.homelinux.net/~stf/
OpenPGP: DFD9 0146 3794 9CF6 17EA D63F DBF5 8AA8 3B31 FE8A
 
G

Goran Pusic

But calling convention is part of the function machine code, isn't it?
So I guess this is generated in compilation phase...





So if the function in question (the one in C++, with extern "C")
receives a function pointer, and calls it, it will be called in C++
convention (the current one for the compiler+architecture)?... :-O

How to make it call this anonymous function pointer in C convention?

Short answer: look up you compiler documentation. This is compiler-
dependent.

Long answer:

It doesn't look like you have read posts here. There is no such thing
as "C (or C++) calling convention".

There is "my compiler does X when I call a C function". It's __all__
compiler/compiler version/software/hardware platform dependent! And on
any given compiler, there are several options, even for C!

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).

In reality, platform APIs specify these things, so compilers align.
And since both C and C++ code need to call system APIs, it's
effectively platform that decides (part of) this list.

Goran.
 
B

BGB / cr88192

James Kanze said:
On 08/25/10 02:50 PM, BGB / cr88192 wrote:
[...]
similarly, it is not really "safe" to use C++-based APIs
across library boundaries, nor for that matter to pass
memory or file references between DLL's (this leads to "fun"
sometimes...).
That is very platform specific. Those restrictions don't
apply to Unix or Unix like systems.

Which part of his statement are you referring to? It's not safe
to use C++ based APIs (with std::string, etc.) between code
compiled with different compiler options, with the same
compiler. And there's no problem passing memory or file
references between dynamically loaded object files on any of the
systems I've worked on, Windows or Unix. (We do it all the time
under Windows, here, and we did it regularly under Solaris and
Linux where I was before.)

this may depend some on the specific compiler, ...
for example, I have not seen this problem pop up with Cygwin or MinGW, but
it pops up fairly often with MSVC.

the reason I suspect is because they link in the runtime libraries
differently:
Cygwin and MinGW tend to use separate DLL's for the runtime (Cygwin using
'cygwin1.dll', and MinGW using 'msvcrt.dll' and others);
MSVC tends to default to hard-linking the runtime libraries, which can
result in crashing when passing file memory or file references (yes, I have
seen it happen, and the results are fairly consistent, more specifically, it
is malloc()'ed memory and stdio FILE's, ...).

granted, if no one in the other DLL ever tries to do IO on the file, or
release the memory, there is no problem.
usual strategy though is to have wrappers in the original DLL, where one
passes the references back to where they came from to operate on the file or
free memory.

also wrapping IO operations also makes it work, so long as the IO is done in
the original DLL...


note that this issue does not apply to memory of files opened via Win32 API
calls (GlobalAlloc, VirtualAlloc, ...), since these are handled differently.


but, yes, this is a fairly platform-specific issue...
 
B

BGB / cr88192

James Kanze said:
How can it? Things like the layout of the vtable are part of
the calling conventions, and C++ can't possibly use the same
ones as C here.

simply:
C doesn't have vtables (or, at least, compiler generated ones);
in the C++ case, they are structures.

effectively, then, vtables are part of the ABI, but are not part of the
calling convention.

Except on Intel, the first argument *is* usually in a register.

not in cdecl or stdcall...
cdecl and stdcall tend to pass *everything* on the stack.

64-bit Windows and Linux pass arguments in registers.
fastcall also uses registers, but fastcall is rarely the default convention
(usually it has to be specified manually).

thiscall (typical on Windows) passes 'this' in ecx, but AFAIK this does not
extend to any other (non-this) arguments.

That's not true, and I've done it on many platforms.

something can easily "work" in many cases, but still not be "safe" in a
portability sense.
if one can do it, they can declare that it "works on most platforms of
interest", which may exclude some edge cases (for example, most PC or server
targetted code will not work on embedded systems, ...).


as for C++ ABI's, the main issue is that MSVC and MinGW on Windows use
different C++ ABI's, and so if one wants to support use of either compiler
(with pre-existing binary code), it is best to avoid using C++ as a basis
for API's.

other compilers tend to have other ABI's as well, and so this leaves the C
ABI as the "most portable" option.


using 'extern "C"' generally works without issue though, so long as one
fully adheres to C restrictions at the API level.

MSVC does what you tell it in this regard. If you tell it to
give each DLL its own local C library, when you don't want to,
it's nobody's fault but your own.

this is the default behavior.
one has to tell it to do otherwise, but then it uses 'msvcr80.dll', which
has to be supplied manually on WinXP.

I don't know about MinGW or Cygwin, but under most Unix, it's
also possible to arrange things so that each shared object has
its own free space arena as well, if this is what you want.

yes, but this is not necessarily a desirable feature, and is actually kind
of annoying sometime...
 
M

Marc

So if the function in question (the one in C++, with extern "C")
receives a function pointer, and calls it, it will be called in C++
convention (the current one for the compiler+architecture)?... :-O

How to make it call this anonymous function pointer in C convention?

"function" and "C-linkage function" are 2 different types in C++.
Indeed, you can even check that a function like qsort, which takes a
comparison function as argument, is overloaded so it can take either a
C++ function or a C function (well, you can't with g++, which wrongly
considers them as the same type).

Note that by default, a function pointer is a C++ function pointer,
except inside an extern "C" block where it is a C function pointer. If
you want to mix (use C function pointers in a C++ function for
instance), you need a typedef.
 
J

James Kanze

James Kanze said:
On 08/25/10 02:50 PM, BGB / cr88192 wrote:
[...]
similarly, it is not really "safe" to use C++-based APIs
across library boundaries, nor for that matter to pass
memory or file references between DLL's (this leads to "fun"
sometimes...).
That is very platform specific. Those restrictions don't
apply to Unix or Unix like systems.
Which part of his statement are you referring to? It's not safe
to use C++ based APIs (with std::string, etc.) between code
compiled with different compiler options, with the same
compiler. And there's no problem passing memory or file
references between dynamically loaded object files on any of the
systems I've worked on, Windows or Unix. (We do it all the time
under Windows, here, and we did it regularly under Solaris and
Linux where I was before.)
this may depend some on the specific compiler, ...
for example, I have not seen this problem pop up with Cygwin
or MinGW, but it pops up fairly often with MSVC.

I've not seen it with any compiler.
the reason I suspect is because they link in the runtime libraries
differently:
Cygwin and MinGW tend to use separate DLL's for the runtime (Cygwin using
'cygwin1.dll', and MinGW using 'msvcrt.dll' and others);
MSVC tends to default to hard-linking the runtime libraries,

As far as I can tell, VC++ doesn't default to anything. You
always have to specify: /MD or /MDd.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top