www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can't assign extern(C) function pointer to D variable?

reply XavierAP <n3minis-git yahoo.es> writes:
I was surprised when it didn't compile, though I immediately 
found it understandable...
Already read through https://dlang.org/spec/interfaceToC.html
and https://wiki.dlang.org/Bind_D_to_C

Is it really the case (that an extern(C) function pointer cannot 
be assigned to a D variable)? Or is it a matter of annotating 
with the right attributes? If so, how?

Otherwise I'm interested in the best or most concise workaround. 
Is there a better one? I came up with a template solution:

https://github.com/XavierAP/game-king/blob/master/source/scope_cleanup.d

The problem I had was that this ScopeCleanup struct could not be 
constructed passing a pointer to a function imported from C (from 
the SDL library; you can browse around the same repo to see its 
usage; it's just a toy project that's barely started).
Nov 22 2022
next sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Tuesday, 22 November 2022 at 21:11:37 UTC, XavierAP wrote:
 I was surprised when it didn't compile, though I immediately 
 found it understandable...
 Already read through https://dlang.org/spec/interfaceToC.html
 and https://wiki.dlang.org/Bind_D_to_C

 [...]
You need to create an alias containing your callback type. ```d alias DCallback = extern(C) void function(); DCallback cb; cb = yourCFunction; ```
Nov 22 2022
parent XavierAP <n3minis-git yahoo.es> writes:
On Tuesday, 22 November 2022 at 21:32:43 UTC, Hipreme wrote:
 You need to create an alias containing your callback type.
Thanks both!! I have all the pieces of the puzzle. I'm actually staying with the wrapping template solution. (Because the strongly typed one turns out too convoluted, and because it allows the remaining ScopeCleanup struct to be more general purpose, for non-C functions, and for functions that don't return void but an error code which I want to discard.) The first problem was indeed that a C function pointer "is not" a D one. So annotating the variable with extern(C) can indeed solve it. I had actually tried this, but it was not compiling for another reason. The next reason (as you see in the GitHub link) is that the variable in question is a (constructor) parameter. D can't seem to compile extern(C) inlined somewhere else. Indeed aliasing takes care of this second problem: alias CFunction = extern(C) void function(); /// RAII object that does nothing but calling, when destructed, the function passed at construction. struct ScopeCleanup { disable this(); this(CFunction cleanup) { this.cleanup = cleanup; } ~this() { cleanup(); } CFunction cleanup; } Now this module compiles. BUT the code trying to call this constructor doesn't compile, when called with C function such as SDL_Quit imported from the SDL lib, or IMG_Quit imported from the SDL_image lib. From the compiler error I learn that the imported function is not only extern(C) but also nothrow nogc. Fair enough, I add it to the alias. BUT still no good, because (as I learn from the same compiler error) this binding imports these functions as extern(C) void function() nothrow nogc* with this final "*" this turns out, from the D point of view, a "pointer to a function pointer" XD so it has to be called/de-referenced in this way (in destructor): alias CFunctionPtr = extern(C) void function() nothrow nogc*; /// RAII object that does nothing but calling, when destructed, the function passed at construction. struct ScopeCleanup { disable this(); this(CFunctionPtr cleanup) { this.cleanup = cleanup; } ~this() { (*cleanup)(); } CFunctionPtr cleanup; } Thanks guys for the learning, I'm staying with the template solution (thanks D), but let me know if you have more insights.
Nov 22 2022
prev sibling parent ag0aep6g <anonymous example.com> writes:
On 22.11.22 22:11, XavierAP wrote:
 I was surprised when it didn't compile, though I immediately found it 
 understandable...
 Already read through https://dlang.org/spec/interfaceToC.html
 and https://wiki.dlang.org/Bind_D_to_C
 
 Is it really the case (that an extern(C) function pointer cannot be 
 assigned to a D variable)? Or is it a matter of annotating with the 
 right attributes? If so, how?
Works for me: import core.stdc.stdio: puts; auto p1 = &puts; extern (C) int function(const char* s) p2 = &puts; If you're trying to assign an `extern (C)` function pointer to an `extern (D)` one (the default), that cannot work. The compiler would emit code using D's calling convention, but the called function would assume C's calling convention.
Nov 22 2022