Binding D to C
Jacob Carlborg
doob at me.com
Fri May 17 00:44:14 PDT 2013
On 2013-05-16 02:37, Walter Bright wrote:
> http://www.gamedev.net/page/resources/_/technical/game-programming/binding-d-to-c-r3122
>
>
> http://www.reddit.com/r/programming/comments/1eerd9/binding_d_to_c/
>
> https://news.ycombinator.com/newest
It's a good article. I haven't read it completely to the end but I would
like to mention a few things.
You didn't mention macros, global variables or inline functions. I think
I've seen inline functions somewhere.
Global Variables
Global variables need to have an extra "extern" and the __gshared
storage. Example in C:
int a;
Translated to D:
extern (C) extern __gshared int a;
For TLS variables __gshared is not used.
Typedefs
When I do a binding I'm trying to figure out why they used a typedef in
the first place. There's a couple of reasons:
* To get a fixed type on all platforms. In the C language there are no
fixed types, it's just relations between the sizes of the types. I.e.
long => int => short => char, or something like that.
In this case, use the native D type. In D a given type has a fixed size
on all platforms (except for real). Examples of these can be: "int8_t",
"uint16_t", "uint32_t" and so on.
* To get different sizes on different platforms. For example, a 32bit
value of 32bit platforms and a 64bit value of 64bit platforms. In this
case you're basically forced to use an alias.
* Opaque types. Perhaps the API is hiding the actual type behind a void*
or for other reasons uses a void*. Then it uses a tyepdef on top of that
to give it an idea of what type we're dealing with.
In this case use the typedef.
* The typedef is well known in the API. Examples of this would be GLint.
I don't remember why they use typedefs but if I recall correctly GLint
is used in all examples, tutorials, books and so on.
In this case it's best to the typedef.
* Hiding a complex type. An example of this could be function pointers.
In this case use the typedef.
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. The
following is syntactically invalid in D:
void foo (extern(C) void function () callback);
Use an alias:
alias extern (C) void function () Callback;
void foo (Callback callback);
* When using a cast with a specific linkage. You won't see this in a
binding, if you're not converting inline functions. This is invalid in D
as well:
void* foo;
...
auto bar = cast(extern (C) void function ()) foo;
Use the same approach as above.
Structs/Unions
You actually didn't mention unions at all but basically all the same
rules that apply when translating structs apply to unions as well. Two
other things that you didn't mention was nested structs and anonymous
structs.
Structs
* For named structs in typedefs I feel a bit undecided of how I want to
have it. You can either just use the name of the typedef in D when
declaring the struct. Or you can use the real name of the struct and
then use an alias as well. In some cases the actual name of the struct
could be used, i.e. "struct foo".
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. Example:
struct
{
int a;
int b;
} c;
Translate to:
struct _AnonymousStruct1
{
int a;
int b;
}
_AnonymousStruct1 c;
Any name can be used in this case. In my tool, DStep, for automatically
generating bindings I'm using names similar to above.
* If an anonymous struct is used in a typedef just use the name of the
typedef. No alias is required in the D code in this case. I actual
noticed now that you have this example.
Nested structs
I always fail to remember how these should be translated to D.
* For nested structs that are named. Example:
struct Foo
{
int a;
struct Bar
{
int b;
} bar;
}
In this case translate it to a named struct in D as well:
struct Foo
{
int a;
struct Bar
{
int b;
}
Bar bar;
}
* For nested struct that are anonymous. Example:
struct Foo
{
int a;
struct
{
int b;
} bar;
}
In this case you could translate it to an anonymous struct in D as well:
struct Foo
{
int a;
struct
{
int b;
}
}
The problem with this is that the API changes. Instead of accessing "b"
like this:
struct Foo foo;
foo.bar.b = 1;
You would do like this:
Foo foo;
foo.b = 1;
I actually looked at the documentation now and see that this example is
not used anymore:
http://dlang.org/interfaceToC.html
http://dlang.org/htod.html
It's still on the D1 page:
http://digitalmars.com/d/1.0/htomodule.html
--
/Jacob Carlborg
More information about the Digitalmars-d
mailing list