[Home]
[Search]
[D]
Last update Sep 4, 2003
Converting C .h Files to D Modules
While D cannot directly compile C source code, it can easily
interface to C code, be linked with C object files, and call
C functions in DLLs.
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 support
a text 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.
Remove all the #if, #ifdef, #include,
etc. statements.
Linkage
Generally, surround the entire module with:
extern (C)
{
...file contents...
}
to give it C linkage.
Types
A little global search and replace will take care of renaming
the C types to D types. The following table shows a typical mapping
for 32 bit C code:
C type
| D type
|
long double
| real
|
unsigned long long
| ulong
|
long long
| long
|
unsigned long
| uint
|
long
| int
|
unsigned
| uint
|
unsigned short
| ushort
|
signed char
| byte
|
unsigned char
| ubyte
|
wchar_t
| wchar or dchar
|
bool
| int
|
NULL
Or ((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. However, one can also replace:
L"string"
with:
cast(wchar[])"string"
Macros
Lists of macros like:
#define FOO 1
#define BAR 2
#define ABC 3
#define DEF 40
can be replaced with:
enum
{ FOO = 1,
BAR = 2,
ABC = 3,
DEF = 40
}
or with:
const int FOO = 1;
const int BAR = 2;
const int ABC = 3;
const int DEF = 40;
Function style macros, such as:
#define MAX(a,b) ((a) < (b) ? (b) : (a))
can be replaced with functions:
int MAX(int a, int b) { return (a < b) ? b : a); }
Declaration Lists
D doesn't allow declaration lists to change the type.
Hence:
int *p, q, t[3], *s;
should be written as:
int* p, s;
int q;
int[3] t;
Void Parameter Lists
Functions that take no parameters:
int foo(void);
are in D:
int foo();
Const Type Modifiers
D has const as a storage class, not a type modifier. Hence, just
drop any const used as a type modifier:
void foo(const int *p, char *const q);
becomes:
void foo(int* p, char* q);
Typedef
alias is the D equivalent to the C typedef:
typedef int foo;
becomes:
alias int foo;
Structs
Replace declarations like:
typedef struct Foo
{ int a;
int b;
} Foo, *pFoo, *lpFoo;
with:
struct Foo
{ int a;
int b;
}
alias Foo* pFoo, lpFoo;
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:
#pragma pack(1)
struct Foo
{
int a;
int b;
};
#pragma pack()
becomes:
struct Foo
{
align (1):
int a;
int b;
}
Nested Structs
struct Foo
{
int a;
struct Bar
{
int c;
} bar;
};
struct Abc
{
int a;
struct
{
int c;
} bar;
};
becomes:
struct Foo
{
int a;
struct Bar
{
int c;
}
Bar bar;
};
struct Abc
{
int a;
struct
{
int c;
}
};
__cdecl, __pascal, __stdcall
int __cdecl x;
int __cdecl foo(int a);
int __pascal bar(int b);
int __stdcall abc(int c);
become:
extern (C) int x;
extern (C) int foo(int a);
extern (Pascal) int bar(int b);
extern (Windows) int abc(int c);
__declspec(dllimport)
__declspec(dllimport) int __stdcall foo(int a);
becomes:
export extern (Windows) int foo(int a);
__fastcall
Unfortunately, D doesn't support the __fastcall convention.
Therefore, a shim will be needed, either written in C:
int __fastcall foo(int a);
int myfoo(int a)
{
return foo(int a);
}
and compiled with a C compiler that supports __fastcall and
linked in, or compile the above, disassemble it with
obj2asm
and insert it in a D myfoo shim with inline assembler.
Copyright (c) 2003 by Digital Mars, All Rights Reserved