· Lexical · Modules · Declarations · Types · Properties · Attributes · Pragmas · Expressions · Statements · Arrays · Structs & Unions · Classes · Interfaces · Enums · Functions · Operator Overloading · Templates · Mixins · Contracts · Conditional Compilation · Handling errors · Garbage Collection · Memory Management · Floating Point · Inline Assembler · Documentation Comments · Interfacing To C · Portability Guide · Embedding D in HTML · Named Character Entities · Application Binary Interface |
Interfacing to CD is designed to fit comfortably with a C compiler for the target system. D makes up for not having its own VM by relying on the target environment's C runtime library. It would be senseless to attempt to port to D or write D wrappers for the vast array of C APIs available. How much easier it is to just call them directly.This is done by matching the C compiler's data types, layouts, and function call/return sequences. Calling C FunctionsC functions can be called directly from D. There is no need for wrapper functions, argument swizzling, and the C functions do not need to be put into a separate DLL.The C function must be declared and given a calling convention, most likely the "C" calling convention, for example: extern (C) int strcmp(char* string1, char* string2);and then it can be called within D code in the obvious way: import std.string; int myDfunction(char[] s) { return strcmp(std.string.toStringz(s), "foo"); }There are several things going on here:
// myfunc() can be called from any C function extern (C) { void myfunc(int a, int b) { ... } } Storage AllocationC code explicitly manages memory with calls to malloc() and free(). D allocates memory using the D garbage collector, so no explicit free's are necessary.D can still explicitly allocate memory using c.stdlib.malloc() and c.stdlib.free(), these are useful for connecting to C functions that expect malloc'd buffers, etc. If pointers to D garbage collector allocated memory are passed to C functions, it's critical to ensure that that memory will not be collected by the garbage collector before the C function is done with it. This is accomplished by:
The garbage collector does not scan the stacks of threads not created by the D Thread interface. Nor does it scan the data segments of other DLL's, etc. Data Type Compatibility
These equivalents hold for most 32 bit C compilers. The C standard does not pin down the sizes of the types, so some care is needed. Calling printf()This mostly means checking that the printf format specifier matches the corresponding D data type. Although printf is designed to handle 0 terminated strings, not D dynamic arrays of chars, it turns out that since D dynamic arrays are a length followed by a pointer to the data, the %.*s format works perfectly:void foo(char[] string) { printf("my string is: %.*s\n", string); }The printf format string literal in the example doesn't end with \0. This is because string literals, when they are not part of an initializer to a larger data structure, have a \0 character helpfully stored after the end of them. An improved D function for formatted output is std.stdio.writef(). Structs and UnionsD structs and unions are analogous to C's.C code often adjusts the alignment and packing of struct members with a command line switch or with various implementation specific #pragma's. D supports explicit alignment attributes that correspond to the C compiler's rules. Check what alignment the C code is using, and explicitly set it for the D struct declaration. D does not support bit fields. If needed, they can be emulated with shift and mask operations. Interfacing to C++D does not provide an interface to C++. Since D, however, interfaces directly to C, it can interface directly to C++ code if it is declared as having C linkage.D class objects are incompatible with C++ class objects. |