Introduction

The interface to C code is normally found in C .h files. So, the trick to connecting with C code is in converting C .h files to D modules. This turns out to be difficult to do mechanically since inevitably some human judgement must be applied. This is a guide to doing such conversions.

Preprocessor

.h files can sometimes be a bewildering morass of layers of macros, #include files, #ifdef's, etc. D doesn't include a text preprocessor like the C preprocessor, so the first step is to remove the need for it by taking the preprocessed output. For DMC (the Digital Mars C/C++ compiler), the command:

dmc -c program.h -e-l

will create a file program.lst which is the source file after all text preprocessing.

For gcc (GNU Compiler Collection), use the command:

gcc-E-P program.h > program.lst

Remove all the #if, #ifdef, #include, etc. statements.

Linkage

Generally, surround the entire module with:

extern(C){/* ...file contents... */}

to give it C linkage.

Global variables

Global variables need to have an extra extern and the __gshared storage.

The C Way

int a;

The D Way

extern (C) extern __gshared int a;

For TLS variables __gshared is not used.

Types

A little global search and replace will take care of renaming the C types to D types. The following tables show typical mappings for 32 bit and 64 bit C code.
Note that there is a difference between them according to the type long. For convencience D offers the type alias core.stdc.config.c_ulong and core.stdc.config.c_long.

Also note that the following lists sometimes show the implicit C variant, e.g., long long instead of its equivalent explicit variant long long int.

For 32 bit systems:

Mapping C type to D type

C type

D type

long double

real

unsigned long long

ulong

long long

long

unsigned long

uint

long

int

unsigned int

uint

int

int

unsigned short

ushort

signed char

byte

unsigned char

ubyte

wchar_t

wchar or dchar

bool

bool, byte, int

size_t

size_t

ptrdiff_t

ptrdiff_t

For 64 bit systems:

Mapping C type to D type

C type

D type

long double

real

unsigned long long

ulong

long long

long

unsigned long

uint (Windows) / ulong (Unix)

long

int (Windows) / long (Unix)

unsigned

uint

unsigned int

int

unsigned short

ushort

signed char

byte

unsigned char

ubyte

wchar_t

wchar or dchar

bool

bool, byte, int

size_t

size_t

ptrdiff_t

ptrdiff_t

NULL

NULL and ((void*)0) should be replaced with null.
Numeric Literals
Any ‘L’ or ‘l’ numeric literal suffixes should be removed, as a C long is (usually) the same size as a D int. Similarly, ‘LL’ suffixes should be replaced with a single ‘L’. Any ‘u’ suffix will work the same in D.

String Literals

In most cases, any ‘L’ prefix to a string can just be dropped, as D will implicitly convert strings to wide characters if necessary.

Declaration Lists

Void Parameter Lists

Functions that take no parameters:

The C Way

int foo(void);

are in D:

The D Way

int foo();

Extern Global C Variables

Whenever a global variable is declared in D, it is also defined. But if it's also defined by the C object file being linked in, there will be a multiple definition error. To fix this problem, use the extern storage class. For example, given a C header file named foo.h:

The C Way

struct Foo {};struct Foo bar;

It can be replaced with the D modules, foo.d:

The D Way

struct Foo {}extern(C){extern Foo bar;}

Typedef

alias is the D equivalent to the C typedef:

The C Way

typedefint foo;

becomes:

The D Way

alias foo =int;

Function pointers

With function pointers there are (at least) two cases where an alias have to be used, instead of a function pointer.

When declaring function parameters with a specific linkage.

When using a cast with a specific linkage. You won't see this in a binding, if you're not converting inline functions.

Structs

Anonymous structs

If an anonymous struct is used directly to declare a variable you're forced to invent a name for the struct in D, since D doesn't support anonymous structs.

The C Way

struct{int a;int b;} c;

Translate to:

The D Way

struct _AnonymousStruct1
{int a;int b;}
_AnonymousStruct1 c;

Any name can be used in this case.

Struct Member Alignment

A good D implementation by default will align struct members the same way as the C compiler it was designed to work with. But if the .h file has some #pragma's to control alignment, they can be duplicated with the D align attribute: