Reading — step 1 of 4
Learn
D was designed for smooth C interop. Plus a -betterC mode that disables D's runtime entirely.
Calling C from D
import std.stdio;
extern (C) int strlen(const char* s);
extern (C) char* strcpy(char* dest, const char* src);
void main() {
const char* s = "hello";
writeln("length: ", strlen(s));
}
extern (C) declares the symbol uses C calling convention. The C standard library is available without explicit imports — most linkers find strlen automatically.
For stdlib bindings, core.stdc.* modules:
import core.stdc.stdio; // printf, fopen, etc.
import core.stdc.stdlib; // malloc, free
import core.stdc.string; // strlen, strcmp
D pointers and C pointers
They're identical at the binary level:
import core.stdc.stdlib;
int* p = cast(int*)malloc(int.sizeof * 100);
scope (exit) free(p);
p[0] = 42;
writeln(p[0]);
C++ interop
extern (C++) {
class Foo {
void doThing();
}
}
D can call C++ classes too — including non-virtual methods, virtual dispatch, even C++ templates (with extern(C++) class).
Calling D from C
Mark D functions as extern(C):
extern (C) int compute_thing(int x) {
return x * x;
}
The C side declares it normally:
extern int compute_thing(int x);
Compile D with dmd -c to produce an object file, then link with C code.
betterC mode
Compile D without the runtime — no GC, no exceptions, no module ctors:
dmd -betterC main.d
Useful for:
- Embedded systems (microcontrollers)
- Bootloaders / kernels
- Calling D from non-D languages without runtime overhead
- Linking into existing C/C++ projects without disrupting their model
In -betterC:
- No
class(usestructonly) - No
throw/catch(use error codes) - No
string(usechar*orconst(char)[]) - No standard library (use
core.stdc.*) - Templates and CTFE still work
// betterC example
extern (C) int main() {
import core.stdc.stdio;
printf("hello, betterC\n");
return 0;
}
This compiles to a tiny binary — a couple KB instead of D's typical 1 MB+ minimum due to runtime.
ImportC
D 2.097+ can import C code directly:
import mylib; // mylib.c parsed at compile time
No bindings needed. The D compiler parses C and exposes symbols.
Why this matters
D can drop into existing C/C++ codebases without forcing a rewrite. Mix D with C for the parts where D's productivity helps; keep C for the legacy core. This is how Sociomantic and Weka built large D systems on top of C foundations.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…