Passing opaque struct between functions/modules

Maxim Fomin maxim at maxim-fomin.ru
Thu Jan 24 05:52:45 PST 2013


On Wednesday, 23 January 2013 at 16:33:08 UTC, Sarath Kumar wrote:
> DMD v2.61; openSUSE 12.1
>
> Source:
> -------
> libA.d:
>
> module libA;
>
> extern (C)
> {
>         struct Opaque;
>
>         Opaque* getObject();
>
>         void doSomething(Opaque *);
> }
> ----------
> libB.d:
>
> module libB;
>
> extern (C)
> {
>         struct Opaque;
>
>         void doAction(Opaque *);
> }
> -----------
> bug.d
>
> import libA, libB;
>
> int main(string[] args)
> {
>         auto opaque = libA.getObject();
>         libA.doSomething(opaque); // this is okay
>         libB.doAction(opaque);  // but this is not, compiler 
> error here
>         return 0;
> }
>
> When I compile the above files, I get the below error.
> $ rdmd bug.d
> bug.d(7): Error: function libB.doAction (Opaque*) is not 
> callable using argument types (Opaque*)
> bug.d(7): Error: cannot implicitly convert expression (opaque) 
> of type Opaque* to Opaque*
>
> If I do an explicit cast, libB.Opaque*, for opaque in line 7, 
> bug.d, I get completely different set of errors.
>
> $ rdmd bug.d
> libB.d(5): Error: struct libB.Opaque unknown size
> libB.d(5): Error: struct libB.Opaque no size yet for forward 
> reference
> libB.d(5): Error: struct libB.Opaque unknown size
> libB.d(5): Error: struct libB.Opaque no size yet for forward 
> reference
> libA.d(5): Error: struct libA.Opaque unknown size
> libA.d(5): Error: struct libA.Opaque no size yet for forward 
> reference
>
> Can someone please tell me the right way to pass an opaque 
> object between module's functions.
>
> --
> Thanks,
> Sarath

You have hit one of the D problems regarding extern(). The first 
problem is that extern(C)-declared objects inside functions are 
still mangled, the other problem is that extern(C) Type var; 
still creates var object, unlike C does (except when Type is a 
function pointer).

The following D program is compiled and linked:

extern(C) int i;

void main()
{
	i = 0;
}

However, a C equivalent would result in linking error due to 
unresolved i reference.

So, what you are really doing is unusable. By the way, doing this 
way you are actually defining two different structs, libA.Opaque 
and libB.Opaque. Compiler is right in this case, because these 
types are incompatible, but it should print full names to show 
the difference explicitly.

If you are working with C library, you can use following scheme:
------main.d------------
extern extern(C) struct Opaque;

extern extern(C) Opaque* getObject();


void main()
{
	Opaque* ptr = getObject();
}
-----struct.c-----------
struct Opaque
{
	int i;
	double d;
};

struct Opaque op;

struct Opaque* getObject()
{
	return &op;
}
------------------------

and if you are using D code, you should use .di files.


More information about the Digitalmars-d-learn mailing list