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