Can't assign extern(C) function pointer to D variable?
XavierAP
n3minis-git at yahoo.es
Tue Nov 22 22:26:02 UTC 2022
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.
More information about the Digitalmars-d-learn
mailing list