$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Interfacing to C, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_ITEM calling_c_functions, Calling C Functions) $(HEADERNAV_ITEM storage_allocation, Storage Allocation) $(HEADERNAV_ITEM data_type_compat, Data Type Compatibility) $(HEADERNAV_ITEM passing_d_array, Passing D Array Arguments to C Functions) $(HEADERNAV_ITEM calling_printf, Calling printf()) $(HEADERNAV_ITEM structs_and_unions, Structs and Unions) $(HEADERNAV_ITEM callbacks, Callbacks) $(HEADERNAV_ITEM using-c-libraries, Using Existing C Libraries) $(HEADERNAV_ITEM c-globals, Accessing C Globals) ) $(DDOC_BLANKLINE ) $(P D 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. ) $(DDOC_BLANKLINE ) $(P This is done by matching the C compiler's data types, layouts, and function call/return sequences. ) $(DDOC_BLANKLINE )

$(LNAME2 calling_c_functions, Calling C Functions)

$(DDOC_BLANKLINE ) $(P C 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. ) $(DDOC_BLANKLINE ) $(P The C function must be declared and given a calling convention, most likely the "C" calling convention, for example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (C) $(D_KEYWORD int) strcmp($(D_KEYWORD const) $(D_KEYWORD char)* string1, $(D_KEYWORD const) $(D_KEYWORD char)* string2); ) $(DDOC_BLANKLINE ) and then it can be called within D code in the obvious way: $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD import) std.string; $(D_KEYWORD int) myDfunction($(D_KEYWORD char)[] s) { $(D_KEYWORD return) strcmp(std.string.toStringz(s), $(D_STRING "foo")); } ) $(DDOC_BLANKLINE ) $(P There are several things going on here:) $(DDOC_BLANKLINE ) $(UL $(LI D understands how C function names are "mangled" and the correct C function call/return sequence.) $(DDOC_BLANKLINE ) $(LI C functions cannot be overloaded with another C function with the same name.) $(DDOC_BLANKLINE ) $(LI There are no $(D __cdecl), $(D __far), $(D __stdcall), $(LINK2 http://www.digitalmars.com/ctg/ctgLanguageImplementation.html#declspec, $(D __declspec)), or other such C $(LINK2 http://www.digitalmars.com/ctg/ctgLanguageImplementation.html#extended, extended type modifiers) in D. These are handled by $(LINK2 attribute.html#linkage, linkage attributes), such as $(D extern (C)).) $(DDOC_BLANKLINE ) $(LI There is no volatile type modifier in D. To declare a C function that uses volatile, just drop the keyword from the declaration.) $(DDOC_BLANKLINE ) $(LI Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated.) $(DDOC_BLANKLINE ) ) $(DDOC_BLANKLINE ) $(P C code can correspondingly call D functions, if the D functions use an attribute that is compatible with the C compiler, most likely the extern (C):) $(DDOC_BLANKLINE ) $(D_CODE $(D_COMMENT // myfunc$(LPAREN)$(RPAREN ) can be called from any C function )$(D_KEYWORD extern) (C) { $(D_KEYWORD void) myfunc($(D_KEYWORD int) a, $(D_KEYWORD int) b) { ... } } ) $(DDOC_BLANKLINE )

$(LNAME2 storage_allocation, Storage Allocation)

$(DDOC_BLANKLINE ) $(P C code explicitly manages memory with calls to $(LINK2 http://www.digitalmars.com/rtl/stdlib.html#malloc, malloc()) and $(LINK2 http://www.digitalmars.com/rtl/stdlib.html#free, free()). D allocates memory using the D garbage collector, so no explicit frees are necessary. ) $(DDOC_BLANKLINE ) $(P D can still explicitly allocate memory using core.stdc.stdlib.malloc() and core.stdc.stdlib.free(), these are useful for connecting to C functions that expect malloc'd buffers, etc. ) $(DDOC_BLANKLINE ) $(P If pointers to D garbage collector allocated memory are passed to C functions, it's critical to ensure that the memory will not be collected by the garbage collector before the C function is done with it. This is accomplished by: ) $(DDOC_BLANKLINE ) $(UL $(DDOC_BLANKLINE ) $(LI Making a copy of the data using core.stdc.stdlib.malloc() and passing the copy instead.) $(DDOC_BLANKLINE ) $(LI Leaving a pointer to it on the stack (as a parameter or automatic variable), as the garbage collector will scan the stack.) $(DDOC_BLANKLINE ) $(LI Leaving a pointer to it in the static data segment, as the garbage collector will scan the static data segment.) $(DDOC_BLANKLINE ) $(LI Registering the pointer with the garbage collector with the $(DDOC_BLANKLINE ) $(DPLLINK phobos/core_memory.html#addRoot, std.gc.addRoot()) or $(DDOC_BLANKLINE ) $(DPLLINK phobos/core_memory.html#addRange, std.gc.addRange()) calls.) $(DDOC_BLANKLINE ) ) $(DDOC_BLANKLINE ) $(P An interior pointer to the allocated memory block is sufficient to let the GC know the object is in use; i.e. it is not necessary to maintain a pointer to the beginning of the allocated memory. ) $(DDOC_BLANKLINE ) $(P 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 DLLs, etc. ) $(DDOC_BLANKLINE )

$(LNAME2 data_type_compat, Data Type Compatibility)

$(DDOC_BLANKLINE ) $(TABLE2 D And C Type Equivalence, $(ELABORATE_HEADER ) $(TR2 $(TD $(D void)), $(MULTICOL_CELL 2, $(D void) $(TAIL void))) $(TR2 $(TD $(D byte)), $(MULTICOL_CELL 2, $(D signed char) $(TAIL signed char))) $(TR2 $(TD $(D ubyte)), $(MULTICOL_CELL 2, $(D unsigned char) $(TAIL unsigned char))) $(TR2 $(TD $(D char)), $(MULTICOL_CELL 2, $(D char) $(TAIL char, (chars are unsigned in D)))) $(TR2 $(TD $(D wchar)), $(MULTICOL_CELL 2, $(D wchar_t) $(TAIL wchar_t, (when $(D sizeof(wchar_t)) is 2)))) $(TR2 $(TD $(D dchar)), $(MULTICOL_CELL 2, $(D wchar_t) $(TAIL wchar_t, (when $(D sizeof(wchar_t)) is 4)))) $(TR2 $(TD $(D short)), $(MULTICOL_CELL 2, $(D short) $(TAIL short))) $(TR2 $(TD $(D ushort)), $(MULTICOL_CELL 2, $(D unsigned short) $(TAIL unsigned short))) $(TR2 $(TD $(D int)), $(MULTICOL_CELL 2, $(D int) $(TAIL int))) $(TR2 $(TD $(D uint)), $(MULTICOL_CELL 2, $(D unsigned) $(TAIL unsigned))) $(DDOC_BLANKLINE ) $(TR3 $(TD $(D core.stdc.config.c_long)), $(TD $(D long)), $(TD $(D long))) $(TR3 $(TD $(D core.stdc.config.c_ulong)), $(TD $(D unsigned long)), $(TD $(D unsigned long))) $(TR3 $(TD $(D core.stdc.stdint.intptr_t)), $(TD $(D intptr_t)), $(TD $(D intptr_t))) $(TR3 $(TD $(D core.stdc.stdint.uintptr_t)), $(TD $(D uintptr_t)), $(TD $(D uintptr_t))) $(DDOC_BLANKLINE ) $(TR3 $(TD $(D long)), $(TD $(D long long)), $(TD $(D long) (or $(D long long)))) $(TR3 $(TD $(D ulong)), $(TD $(D unsigned long long)), $(TD $(D unsigned long) (or $(D unsigned long long)))) $(DDOC_BLANKLINE ) $(TR2 $(TD $(D float)), $(MULTICOL_CELL 2, $(D float) $(TAIL float))) $(TR2 $(TD $(D double)), $(MULTICOL_CELL 2, $(D double) $(TAIL double))) $(TR2 $(TD $(D real)), $(MULTICOL_CELL 2, $(D long double) $(TAIL long double))) $(DDOC_BLANKLINE ) $(TR2 $(TD $(D cdouble)), $(MULTICOL_CELL 2, $(D double _Complex) $(TAIL double _Complex))) $(TR2 $(TD $(D creal)), $(MULTICOL_CELL 2, $(D long double _Complex) $(TAIL long double _Complex))) $(TR2 $(TD $(D struct)), $(MULTICOL_CELL 2, $(D struct) $(TAIL struct))) $(TR2 $(TD $(D union)), $(MULTICOL_CELL 2, $(D union) $(TAIL union))) $(TR2 $(TD $(D enum)), $(MULTICOL_CELL 2, $(D enum) $(TAIL enum))) $(TR2 $(TD $(D class)), $(MULTICOL_CELL 2, $(D ) $(TAIL ,no equivalent))) $(TR2 $(TD $(D type *)), $(MULTICOL_CELL 2, $(D type *) $(TAIL type *))) $(TR2 $(TD $(D type[dim])), $(MULTICOL_CELL 2, $(D type[dim]) $(TAIL type[dim]))) $(TR2 $(TD $(D type[dim], type()[dim])), $(MULTICOL_CELL 2, $(D type[dim], type()[dim]) $(TAIL ))) $(TR2 $(TD $(D type[])), $(MULTICOL_CELL 2, $(D ) $(TAIL ,no equivalent))) $(TR2 $(TD $(D type1[type2])), $(MULTICOL_CELL 2, $(D ) $(TAIL , no equivalent))) $(TR2 $(TD $(D type function(params))), $(MULTICOL_CELL 2, $(D type(*)(params)) $(TAIL type(*)(params)))) $(TR2 $(TD $(D type delegate(params))), $(MULTICOL_CELL 2, $(D ) $(TAIL , no equivalent))) $(TR2 $(TD $(D size_t)), $(MULTICOL_CELL 2, $(D size_t) $(TAIL size_t))) $(TR2 $(TD $(D ptrdiff_t)), $(MULTICOL_CELL 2, $(D ptrdiff_t) $(TAIL ptrdiff_t))) ) $(DDOC_BLANKLINE ) $(P These equivalents hold for most C compilers. The C standard does not pin down the sizes of the types, so some care is needed. ) $(DDOC_BLANKLINE )

$(LNAME2 passing_d_array, Passing D Array Arguments to C Functions)

$(DDOC_BLANKLINE ) $(P In C, arrays are passed to functions as pointers even if the function prototype says its an array. In D, static arrays are passed by value, not by reference. Thus, the function prototype must be adjusted to match what C expects.) $(DDOC_BLANKLINE ) $(TABLE2 D And C Function Prototype Equivalence, D type, C type $(TROW $(I T)$(B *) , $(I T)$(B [])) $(TROW $(B ref) $(I T)$(B [)$(I dim)$(B ]) , $(I T)$(B [)$(I dim)$(B ]))) $(DDOC_BLANKLINE ) $(P For example:) $(DDOC_BLANKLINE ) $(CCODE void foo(int a[3]) { ... } // C code) $(D_CODE $(D_KEYWORD extern) (C) { $(D_KEYWORD void) foo($(D_KEYWORD ref) $(D_KEYWORD int)[3] a); $(D_COMMENT // D prototype )} ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 calling_printf, Calling printf())

$(DDOC_BLANKLINE ) $(P printf can be directly called from D code:) $(D_CODE $(D_KEYWORD import) core.stdc.stdio; $(D_KEYWORD int) main() { printf($(D_STRING "hello world\n")); $(D_KEYWORD return) 0; } ) $(DDOC_BLANKLINE ) $(P Printing values works as it does in C:) $(D_CODE $(D_KEYWORD int) apples; printf($(D_STRING "there are %d apples\n"), apples); ) $(P Correctly matching the format specifier to the D type is necessary. The D compiler recognizes the printf formats and diagnoses mismatches with the supplied arguments. The specification for the formats used by D is the C99 specification 7.19.6.1. ) $(DDOC_BLANKLINE ) $(P A generous interpretation of what is a match between the argument and format specifier is taken, for example, an unsigned type can be printed with a signed format specifier. Diagnosed incompatibilites are: ) $(DDOC_BLANKLINE ) $(UL $(LI incompatible sizes which may cause argument misalignment) $(LI dereferencing arguments that are not pointers) $(LI insufficient number of arguments) $(LI struct, array and slice arguments are not allowed) $(LI non-pointer arguments to s specifier) $(LI non-Standard formats) $(LI undefined behavior per C99) ) $(DDOC_BLANKLINE )

Strings

$(DDOC_BLANKLINE ) $(P A string cannot be printed directly. But %.*s can be used: ) $(D_CODE string s = $(D_STRING "betty"); printf($(D_STRING "hello %.*s\n"), $(D_KEYWORD cast)($(D_KEYWORD int)) s.length, s.ptr); ) $(P The cast to int is required. ) $(DDOC_BLANKLINE )

size_t and ptrdiff_t

$(DDOC_BLANKLINE ) $(P These use the zu and td format specifiers respectively: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) core.stdc.stdio : printf; $(D_KEYWORD int)* p = $(D_KEYWORD new) $(D_KEYWORD int), q = $(D_KEYWORD new) $(D_KEYWORD int); printf($(D_STRING "size of an int is %zu, pointer difference is %td\n"), $(D_KEYWORD int).sizeof, p - q); ) ) $(DDOC_BLANKLINE )

Non-Standard Format Specifiers

$(DDOC_BLANKLINE ) $(P Non-Standard format specifiers will be rejected by the compiler. Since the checking is only done for formats as string literals, non-Standard ones can be used: ) $(D_CODE $(D_KEYWORD const) $(D_KEYWORD char)* format = $(D_STRING "value: %K\n"); printf(format, value); ) $(DDOC_BLANKLINE )

Modern Formatted Writing

$(DDOC_BLANKLINE ) $(P An improved D function for formatted output is $(CODE std.stdio.writef()). ) $(DDOC_BLANKLINE )

$(LNAME2 structs_and_unions, Structs and Unions)

$(DDOC_BLANKLINE ) $(P D structs and unions are analogous to C's. ) $(DDOC_BLANKLINE ) $(P C code often adjusts the alignment and packing of struct members with a command line switch or with various implementation specific $(HASH )pragmas. 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. ) $(DDOC_BLANKLINE ) $(P D does not support bit fields. If needed, they can be emulated with shift and mask operations, or use the $(LINK2 $(ROOT_DIR )phobos/std_bitmanip.html#bitfields, std.bitmanip.bitfields) library type. $(DPLLINK htod.html, htod) will convert bit fields to inline functions that do the right shift and masks. ) $(DDOC_BLANKLINE ) $(P D does not support declaring variables of anonymous struct types. In such a case, define a named struct in D and make it private:) $(DDOC_BLANKLINE ) $(CCODE union Info // C code { struct { char *name; } file; }; ) $(D_CODE $(D_KEYWORD union) Info $(D_COMMENT // D code ){ $(D_KEYWORD private) $(D_KEYWORD struct) File { $(D_KEYWORD char)* name; } File file; } ) $(DDOC_BLANKLINE )

$(LNAME2 callbacks, Callbacks)

$(DDOC_BLANKLINE ) $(P D can easily call C callbacks (function pointers), and C can call callbacks provided by D code if the callback is an $(D extern(C)) function, or some other linkage that both sides have agreed to (e.g. $(D extern(Windows))).) $(DDOC_BLANKLINE ) $(P Here's an example of C code providing a callback to D code:) $(DDOC_BLANKLINE ) $(CCODE void someFunc(void *arg) { printf("Called someFunc!\n"); } // C code typedef void (*Callback)(void *); extern "C" Callback getCallback(void) { return someFunc; } ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern)(C) $(D_KEYWORD alias) Callback = $(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD int), $(D_KEYWORD int)); $(D_COMMENT // D code )$(D_KEYWORD extern)(C) Callback getCallback(); $(D_KEYWORD void) main() { Callback cb = getCallback(); cb(); $(D_COMMENT // invokes the callback )} ) $(DDOC_BLANKLINE ) $(P And an example of D code providing a callback to C code:) $(DDOC_BLANKLINE ) $(CCODE extern "C" void printer(int (*callback)(int, int)) // C code { printf("calling callback with 2 and 4 returns: %d\n", callback(2, 4)); } ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern)(C) $(D_KEYWORD alias) Callback = $(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD int), $(D_KEYWORD int)); $(D_COMMENT // D code )$(D_KEYWORD extern)(C) $(D_KEYWORD void) printer(Callback callback); $(D_KEYWORD extern)(C) $(D_KEYWORD int) sum($(D_KEYWORD int) x, $(D_KEYWORD int) y) { $(D_KEYWORD return) x + y; } $(D_KEYWORD void) main() { printer(&sum); } ) $(DDOC_BLANKLINE ) $(P For more info about callbacks read the $(LINK2 function.html#closures, closures) section.) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 Using C Libraries, using-c-libraries, Using Existing C Libraries)

$(DDOC_BLANKLINE ) $(P Since D can call C code directly, it can also call any C library functions, giving D access to the smorgasbord of existing C libraries. To do so, however, one needs to write a D interface (.di) file, which is a translation of the C .h header file for the C library into D. ) $(DDOC_BLANKLINE ) $(P For popular C libraries, the first place to look for the corresponding D interface file is the $(LINK2 https://github.com/D-Programming-Deimos/, Deimos Project). If it isn't there already, please write and contribute one to the Deimos Project. ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 C Globals, c-globals, Accessing C Globals)

$(DDOC_BLANKLINE ) $(P C globals can be accessed directly from D. C globals have the C naming convention, and so must be in an $(D extern (C)) block. Use the $(D extern) storage class to indicate that the global is allocated in the C code, not the D code. C globals default to being in global, not thread local, storage. To reference global storage from D, use the $(D __gshared) storage class. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD extern) (C) $(D_KEYWORD extern) $(D_KEYWORD __gshared) $(D_KEYWORD int) x; ) $(DDOC_BLANKLINE ) $(SPEC_SUBNAV_PREV_NEXT ddoc, Embedded Documentation, cpp_interface, Interfacing to C++) ) )