C style callbacks fix for member callbacks

ag0aep6g anonymous at example.com
Sun May 20 23:05:47 UTC 2018


On 05/20/2018 06:48 PM, IntegratedDimensions wrote:
> alias callback = extern(C) int function(const(void) a, void *b, uint c, 
> void* context);

(I'm assuming that `a` is supposed to be a `const(void)*`.)

> Where context acts as this.
> 
> I would like to assign a D method to this callback.
> 
> class
> {
>     callback c;
>     /*extern(C) static*/ int foo(const(void) a, void *b, uint c, void* 
> context);
>
>     this() { c = cast(callback)&foo; }
> }

Unless I'm misunderstanding it, the spec seems to say that the `this` 
pointer is passed as if it was an additional parameter past the last one 
[1].

But that doesn't seem to be true in the implementation. At least on 
Linux x86-64, `this` seems to be a hidden first parameter. So when a 
method is called as a `callback`, `a` becomes `this`, `b` becomes the 
first explicit parameter, `c` the second, and `context` the third. So 
this works:

----
import std.stdio;

alias Callback = extern(C) int function(const(void)* a, void* b, uint c,
     void* context);

class C
{
     int field = 43;
     extern(C) int foo(void* b, uint c, C this_)
     {
         const(void)* a = cast(void*) this;
         writeln(a, " ", b, " ", c, " ", this_.field);
         return 0;
     }
}

void main()
{
     void* a = new int;
     void* b = new int;
     uint c = 42;
     auto obj = new C;
     Callback cb = cast(Callback) (&obj.foo).funcptr;
     cb(a, b, c, cast(void*) obj);
     writeln(a, " ", b, " ", c, " ", obj.field);
         /* For comparison. Should print the same. */
}
----

This is all very hacky, of course. And I don't really know what I'm 
doing there. So obviously, I don't recommend doing this.

But other than hacking it like that, I don't think you can pass a method 
as a `callback` directly.


[1] https://dlang.org/spec/abi.html#parameters


More information about the Digitalmars-d-learn mailing list