This is an old revision of the document!


Lab 07: C/C++ Interoperability and Tooling

Interfacing to C

Calling C functions from D

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. The C function must be declared and given a calling convention, most likely the “C” calling convention, for example:

extern (C) int strcmp(const char* string1, const 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");
}

Calling D functions from C

For D functions to be able to be called from a C context, they should be annotated with the extern(C) attribute:

// test.d
extern (C) int average(int a, int b) { return (a+b)/2; }  

On the C side, the function signature must be provided:

// main.c
int average(int a, int b);
void main()
{
    int a = average(5, 9);
    printf("%d\n", a);     // prints 7;
}

Compilation of the sources is done in the following manner:

dmd -c test.d
gcc -o main.o -c main.c
gcc test.o main.o

Compiling the D and C code to object modules and then linking them into an executable is all that needs to be done. For this to work it is imperative that the label (the function name) is exactly the same on both D and C sides; also both sides need to respect the same calling convention. extern (C) instructs the compiler to mangle the name of the function according to the rules of the C languages; the D calling convention is the same as the C one.

Struct and Unions

D 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 #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. Example:

// test.d
struct A                                                              
{                                                                     
    int a;                                                            
}                                                                     
 
extern(C) int fun(A a)                                                
{                                                                     
    return a.a + 7;                                                                                                                           
}
// main.c
#include <stdio.h>                                                                                                                            
 
struct A
{
    int a;
} a;
 
int fun(struct A a); 
 
void main()
{
    a.a = 6;
    printf("Called fun, response: %d\n", fun(a));
}

Both sides need to define the struct in order to know the layout in memory of the fields.

Using existing C libraries

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.

For popular C libraries, the first place to look for the corresponding D interface file is the Deimos Project. If it isn't there already, and you write one, please contribute it to the Deimos Project.

Accessing C globals

C globals can be accessed directly from D. C globals have the C naming convention, and so must be in an extern (C) block. Use the 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 gshared storage class. <code D> extern (C) __gshared int x; </code> ==== Interfacing to C++ ==== Calling D functions from C++ and viceversa are achieved exactly the same as in the case of C, by using extern(C++). === C++ namespaces === C++ symbols that reside in namespaces can be accessed from D. A namespace can be added to the extern (C++) linkage attribute: <code D> extern (C++, N) int foo(int i, int j, int k); void main() { N.foo(1, 2, 3); foo is in C++ namespace 'N' } </code> === Classes === C++ classes can be declared in D by using the extern (C++) attribute on class, struct and interface declarations. extern (C++) interfaces have the same restrictions as D interfaces, which means that Multiple Inheritance is supported to the extent that only one base class can have member fields. extern (C++) structs do not support virtual functions but can be used to map C++ value types. Unlike classes and interfaces with D linkage, extern (C++) classes and interfaces are not rooted in Object and cannot be used with typeid. === Structs === C++ allows a struct to inherit from a base struct. This is done in D using alias this. === C++ Templates === C++ function and type templates can be bound by using the extern (C++) attribute on a function or type template declaration. Note that all instantiations used in D code must be provided by linking to C++ object code or shared libraries containing the instantiations.

dss/laboratoare/07.1562156922.txt.gz · Last modified: 2019/07/03 15:28 by razvan.nitu1305
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0