On Friday, 26 June 2020 at 00:30:22 UTC, Denis wrote:
I have a two questions about calling C functions from D.
(1) When passing a D callback to a C function, is there a way
to write the code without having to prefix the callback
declaration with "extern(C)"?
It's not a big deal adding the prefix to the D function
declaration. It just seems odd to me to prefix D code with
"extern(C)". For example, the following code works:
extern(C) void cfunc(void function(int));
extern(C) void dcallback(int x) {...} <-- Why extern(C)?
cfunc(&dcallback);
Can this be rewritten, dropping the prefix from the second
line? If not, it would be helpful to know why "extern(C)" is
needed here too.
No, it cannot be dropped. `extern(C)` is required because C and D
are using different calling conventions (D functions are also
mangled). For example, D (at least DMD and LDC) are passing the
arguments to the function in reverse.
(2) Is there a way to restrict the invocation of a linked C
function to one specific D function?
If the C header is defined in one of the core.stdc libraries,
the import statement can either be global or inside a specific
D function -- both work. In contrast, when the C function
prototype is written directly into the D program (as above),
the linker complains unless this declaration is made global. If
it's possible to restrict the scope of the C function to just
one D function, I'll take advantage.
For functions nested in a D language construct (class, struct,
function) the compiler will always use the D mangling, instead of
the C mangling. In theory it would be possible to workaround that
by forcing the mangled name using `pragma(mangle)`, but for some
reason the compiler doesn't allow `pragma(mangle)` inside a
function body, on a nested function declaration.
You can wrap up everything in a struct, as follows:
struct printf
{
pragma(mangle, "printf") extern (C) private static int
printf(in char*, ...);
static int opCall(Args...)(Args args)
{
return printf(args);
}
}
void main()
{
printf("asd\n".ptr);
}
The `printf` function can be called from anywhere within the
module, but not outside the module.
--
/Jacob Carlborg