digitalmars.D.learn - Calling C functions
- Denis (24/24) Jun 25 2020 I have a two questions about calling C functions from D.
- Jacob Carlborg (29/51) Jun 26 2020 No, it cannot be dropped. `extern(C)` is required because C and D
- Denis (11/32) Jun 26 2020 OK, now this makes sense.
- Jacob Carlborg (5/10) Jun 26 2020 No, of course not. How would you otherwise call your `cfunc` function
- Steven Schveighoffer (8/30) Jun 29 2020 Are you sure? On the ABI page [1] , it says "The extern (C) and extern
- Jacob Carlborg (26/29) Jun 29 2020 In that case the documentation is wrong. Here's an example
- Steven Schveighoffer (4/12) Jun 29 2020 Yep, for sure. I'll file an issue. Anyone know why the calling
- Kagamin (5/7) Jun 30 2020 It's easier to enforce left to right evaluation order this way:
- Steven Schveighoffer (7/14) Jun 30 2020 Easier, or more efficient? The cost seems high if it doesn't provide any...
- Jacob Carlborg (13/14) Jun 30 2020 I don't think that's a big issue. Honestly, I don't think it's an
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. (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. (I'm using dmd, if that makes a difference.) Thanks
Jun 25 2020
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
Jun 26 2020
On Friday, 26 June 2020 at 08:15:27 UTC, Jacob Carlborg wrote:On Friday, 26 June 2020 at 00:30:22 UTC, Denis wrote:OK, now this makes sense. I tested calling the same callback function directly from D: it compiled and worked correctly. So at least prefixing the callback function with `extern(C)` doesn't prevent the rest of the D program from calling it too.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?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:I see. Thank you very much for these explanations and code -- the insights are very helpful. Denis
Jun 26 2020
On 2020-06-26 18:54, Denis wrote:OK, now this makes sense. I tested calling the same callback function directly from D: it compiled and worked correctly. So at least prefixing the callback function with `extern(C)` doesn't prevent the rest of the D program from calling it too.No, of course not. How would you otherwise call your `cfunc` function from your original example ;) -- /Jacob Carlborg
Jun 26 2020
On 6/26/20 4:15 AM, Jacob Carlborg wrote:On Friday, 26 June 2020 at 00:30:22 UTC, Denis wrote:Are you sure? On the ABI page [1] , it says "The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system." I'm pretty sure you can use function pointers to D functions for C callbacks, and it should work. -Steve [1] https://dlang.org/spec/abi.html#function_calling_conventionsI 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.
Jun 29 2020
On Monday, 29 June 2020 at 16:34:33 UTC, Steven Schveighoffer wrote:Are you sure? On the ABI page [1] , it says "The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system."In that case the documentation is wrong. Here's an example showing the differences: $ cat foo.c #include <stdio.h> void foo(int a, int b) { printf("a=%d b=%d\n", a, b); } $ clang -c foo.c $ cat main.d pragma(mangle, "foo") extern (D) void foo_extern_d(int, int); pragma(mangle, "foo") extern (C) void foo_extern_c(int, int); void main() { foo_extern_d(1, 2); foo_extern_c(1, 2); } $ dmd main.d foo.o $ ./main a=2 b=1 a=1 b=2 This is on macOS. -- /Jacob Carlborg
Jun 29 2020
On 6/29/20 1:50 PM, Jacob Carlborg wrote:On Monday, 29 June 2020 at 16:34:33 UTC, Steven Schveighoffer wrote:Yep, for sure. I'll file an issue. Anyone know why the calling convention would differ? -SteveAre you sure? On the ABI page [1] , it says "The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system."In that case the documentation is wrong. Here's an example showing the differences:
Jun 29 2020
On Monday, 29 June 2020 at 19:55:59 UTC, Steven Schveighoffer wrote:Yep, for sure. I'll file an issue. Anyone know why the calling convention would differ?It's easier to enforce left to right evaluation order this way: arguments are pushed to stack as they are evaluated, which is pascal calling convention.
Jun 30 2020
On 6/30/20 3:00 AM, Kagamin wrote:On Monday, 29 June 2020 at 19:55:59 UTC, Steven Schveighoffer wrote:Easier, or more efficient? The cost seems high if it doesn't provide any efficiency benefits (i.e. one cannot use extern(D) functions for C callbacks). In any case, I filed an issue: https://issues.dlang.org/show_bug.cgi?id=20993 -SteveYep, for sure. I'll file an issue. Anyone know why the calling convention would differ?It's easier to enforce left to right evaluation order this way: arguments are pushed to stack as they are evaluated, which is pascal calling convention.
Jun 30 2020
On Tuesday, 30 June 2020 at 12:22:15 UTC, Steven Schveighoffer wrote:(i.e. one cannot use extern(D) functions for C callbacks).I don't think that's a big issue. Honestly, I don't think it's an issue at all. BTW, the order of arguments is not the only thing. Variadic functions in D and C are completely different. I don't think it's possible to implement a C style variadic function with D linkage (the language doesn't provide a syntax for it). There's also D specific types which C cannot handle (like arrays and delegates). I'm sure there are other differences in the ABIs. -- /Jacob Carlborg
Jun 30 2020