Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Lamda function-pointer wrapping

64 views
Skip to first unread message

Bonita Montero

unread,
Apr 16, 2020, 2:03:30 PM4/16/20
to
I just wrote a callback for some Windows-API with a lambda. I won-
dered this works although you can't specify a calling convention
for the lambda-function. I first thought that with Windows 64 bit
most of the calling conventions have been leveled (__cdecl, __stdcall
and __fastcall are now the same) so they are now compatible with the
Windows-callbacks. But then I thought, that when I pass them as a
function-pointer my compiler might generate some wrapper-code before
the actual lambda-function. I tested this with a little program:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
auto f = []( int a, int b, int c ) -> int
{
return a + b + c;
};
int (__cdecl *fCdecl)( int, int, int ) = f;
int (__stdcall *fStdCall)( int, int, int ) = f;
int (__fastcall *fFastCall)( int, int, int ) = f;
cout << hex << fCdecl << " " << fStdCall << " " << fFastCall << endl;
}

So compiled with MSVC / 32 bit, I get thee different pointer.
With MSVC / 64 bit, the pointers are all the same.

So what about g++. Are there also differnt calling conventions
whch are adapted in this way ?

Alf P. Steinbach

unread,
Apr 16, 2020, 2:22:52 PM4/16/20
to
g++ needs to conform to a system's conventions in order to be usable on
a system.

However it can accept code that the system compiler doesn't accept, e.g.

(*[]( int x ) -> int { return x; });

Disclaimer: I didn't try this now, but with Visual C++ I would expect an
error because last I time I did something like that it complained about
the calling convention wrappers it itself generated resulting in
ambiguous overload resolution.

- - -

The formal is a very different kettle of fish.

There the question is whether a pointer to function with C++ calling
convention (the default, or `extern "C++") converts implicitly to
pointer to ditto function with C calling convention, `extern "C"`. In
practice it does, of course; that interoparbility and ability to
leverage C libraries was a main design goal. But as far as I know the
formal standard does not in any place permit that.

However, also as far as I know only a Solaris compiler has ever
complained by default, and then as a warning.


- Alf

Paavo Helde

unread,
Apr 16, 2020, 2:34:23 PM4/16/20
to
I guess this depends more on the target architecture and not so much on
the compiler vendor. For example, cygwin g++ 9.3.0 with x86_64-pc-cygwin
target compiles your program and prints 3 identical pointers (after I
added casts to void*, otherwise it printed "1 1 1").

Bonita Montero

unread,
Apr 16, 2020, 11:17:23 PM4/16/20
to
>> I just wrote a callback for some Windows-API with a lambda. I won-
>> dered this works although you can't specify a calling convention
>> for the lambda-function. I first thought that with Windows 64 bit
>> most of the calling conventions have been leveled (__cdecl, __stdcall
>> and __fastcall are now the same) so they are now compatible with the
>> Windows-callbacks. But then I thought, that when I pass them as a
>> function-pointer my compiler might generate some wrapper-code before
>> the actual lambda-function. I tested this with a little program:
>>
>> #include <iostream>
>> #include <iomanip>
>>
>> using namespace std;
>>
>> int main()
>> {
>>      auto f = []( int a, int b, int c ) -> int
>>      {
>>          return a + b + c;
>>      };
>>      int (__cdecl    *fCdecl)(    int, int, int ) = f;
>>      int (__stdcall  *fStdCall)(  int, int, int ) = f;
>>      int (__fastcall *fFastCall)( int, int, int ) = f;
>>      cout << hex << fCdecl << " " << fStdCall << " " << fFastCall <<
>> endl;
>> }
>>
>> So compiled with MSVC / 32 bit, I get thee different pointer.
>> With MSVC / 64 bit, the pointers are all the same.
>>
>> So what about g++. Are there also differnt calling conventions
>> whch are adapted in this way ?

> ... For example, cygwin g++ 9.3.0 with x86_64-pc-cygwin target ^^^^^^^^^^^^^^^^^^^^^^^
> target compiles your program and prints 3 identical pointers

I already said that the most usual calling conventions are the same
in Windows 64 bit.

Bonita Montero

unread,
Apr 17, 2020, 8:25:11 AM4/17/20
to
> So compiled with MSVC / 32 bit, I get thee different pointer.
> With MSVC / 64 bit, the pointers are all the same.

The symbol-names of the functions which should call the lambda
-function contain the name invoker in the disassembly. But when
the compiler sees that the call has a certain overhad against
the lambda, it simply compiles three invokers containing the
lambda-code itself.

0 new messages