www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Qs about structs and their references WRT C functions and variables

reply Rick Mann <rmann-d-lang latencyzero.com> writes:
I'm working on some C bindings, and I need to know a few things that aren't
clear from the spec.

a) If a C function takes a pointer to a struct so that it can fill that struct
(return it), I've found I can write the parameter as "out MyStruct outS", and
things work as expected (I don't take the address of the parameter I pass).

If a function simply takes a struct as input, and therefore I leave off any
qualifier in the D parameter declaration (i.e., "MyStruct inS"), is the struct
still passed by reference? I assume so, but want to be sure.

b) Some of the API's in C pass the entire struct (I question the wisdom of
this). How do I link to these?

c) I need to declare a couple of extern structs. Can I just slap an "extern
(C)" on these and all will be well? The spec seems to indicate that this is so,
and it may be fine; I'm just looking for verification. e.g.:

struct
ControlID
{
	uint		signature;
	int		id;
};
typedef ControlID                       HIViewID;
extern (C)
const HIViewID kHIViewWindowContentID;

TIA,
Rick
Jan 30 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Rick Mann" <rmann-d-lang latencyzero.com> wrote in message 
news:epoqju$26f0$1 digitaldaemon.com...
 I'm working on some C bindings, and I need to know a few things that 
 aren't clear from the spec.

 a) If a C function takes a pointer to a struct so that it can fill that 
 struct (return it), I've found I can write the parameter as "out MyStruct 
 outS", and things work as expected (I don't take the address of the 
 parameter I pass).

Right. 'out' implicitly passes the struct by reference, so if the struct parameter is a return value, then 'out' is the right way to go. That it works with C libraries is something that I didn't know, and something very cool..
 If a function simply takes a struct as input, and therefore I leave off 
 any qualifier in the D parameter declaration (i.e., "MyStruct inS"), is 
 the struct still passed by reference? I assume so, but want to be sure.

No. It's passed by value, just like if you were to write void func(struct SomeStruct s); in C.
 b) Some of the API's in C pass the entire struct (I question the wisdom of 
 this). How do I link to these?

If the struct is fairly small, passing the struct by value probably isn't that much of a performance loss (and might even be a gain, if it accesses the structs members often inside the function). But if it were declared as void func(struct SomeStruct s); in C, then you declare it as extern(C) void func(SomeStruct s); in D.
 c) I need to declare a couple of extern structs. Can I just slap an 
 "extern (C)" on these and all will be well? The spec seems to indicate 
 that this is so, and it may be fine; I'm just looking for verification. 
 e.g.:

 struct
 ControlID
 {
 uint signature;
 int id;
 };
 typedef ControlID                       HIViewID;
 extern (C)
 const HIViewID kHIViewWindowContentID;

 TIA,
 Rick

Hmm.. if I remember correctly, those extern struct declarations have to be in a .d file which is _imported_ but never _compiled_. So you'd have something like importedstructs.d struct ControlID { uint signature; int id; } typedef ControlID HIViewID; extern(C) const HIViewID kHIViewWindowContentID; And then the rest of your program would have: import importedstructs; But you wouldn't put importedstructs.d on the command line when you compile your program.
Jan 30 2007
parent reply Rick Mann <rmann-d-lang latencyzero.com> writes:
Jarrett Billingsley Wrote:

 Right.  'out' implicitly passes the struct by reference, so if the struct 
 parameter is a return value, then 'out' is the right way to go.  That it 
 works with C libraries is something that I didn't know, and something very 
 cool..

It makes for tidy calls where the parameter is used for output. However, I can't seem to do the same for an input parameter. I'd like to do the equivalent of the following C code: void func(const SomeStruct& inS); This is identical to void func(const SomeStruct* inS); but allows me to call it without adding the & in front of the parameter. It's a bit inconsistent that I can do this with an "out" parameter, but not an "in" parameter.
 Hmm.. if I remember correctly, those extern struct declarations have to be 
 in a .d file which is _imported_ but never _compiled_.  So you'd have 
 something like
 
 importedstructs.d
 
 struct ControlID
 {
     uint signature;
     int id;
 }
 
 typedef ControlID HIViewID;
 extern(C) const HIViewID kHIViewWindowContentID;
 
 And then the rest of your program would have:
 
 import importedstructs;
 
 But you wouldn't put importedstructs.d on the command line when you compile 
 your program. 

I finally got to try that code. Seems to work, even with compiling the class in which it's declared. Thanks!
Jan 30 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Rick Mann wrote:
 Jarrett Billingsley Wrote:
 
 Right.  'out' implicitly passes the struct by reference, so if the struct 
 parameter is a return value, then 'out' is the right way to go.  That it 
 works with C libraries is something that I didn't know, and something very 
 cool..

It makes for tidy calls where the parameter is used for output. However, I can't seem to do the same for an input parameter. I'd like to do the equivalent of the following C code: void func(const SomeStruct& inS); This is identical to void func(const SomeStruct* inS); but allows me to call it without adding the & in front of the parameter. It's a bit inconsistent that I can do this with an "out" parameter, but not an "in" parameter.

You could use inout. It's basically a C++ non-const reference.
Jan 30 2007
parent reply Rick Mann <rmann-d-lang latencyzero.com> writes:
Frits van Bommel Wrote:

 You could use inout. It's basically a C++ non-const reference.

Yeah, but it kind of breaks the implied semantics...in this case, the parameter is used as input, and not modified, so the value of the supplied parameter is unaffected by the call.
Jan 30 2007
next sibling parent Mike Parker <aldacron71 yahoo.com> writes:
Rick Mann wrote:
 Frits van Bommel Wrote:
 
 You could use inout. It's basically a C++ non-const reference.

Yeah, but it kind of breaks the implied semantics...in this case, the parameter is used as input, and not modified, so the value of the supplied parameter is unaffected by the call.

For now, it's the only option we have. You can read 'inout' as 'byref'.
Jan 30 2007
prev sibling parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Rick Mann wrote:
 Frits van Bommel Wrote:
 
 You could use inout. It's basically a C++ non-const reference.

Yeah, but it kind of breaks the implied semantics...in this case, the parameter is used as input, and not modified, so the value of the supplied parameter is unaffected by the call.

Why? It *is* modified when you modify it inside the function .. If my information is correct, the difference between out and inout is: - "inout" just passes the struct by reference. - "out" clears the struct before passing it by reference.
Jan 30 2007
parent Rick Mann <rmann-d-lang latencyzero.com> writes:
Hasan Aljudy Wrote:

 
 Why? It *is* modified when you modify it inside the function ..

Well, I mean in the case where you do NOT modify it in the function, and you want to communicate(and even enforce) that contract. Allowing const on parameters would allow the compiler to generate errors in the function.
Jan 31 2007
prev sibling parent reply torhu <fake address.dude> writes:
Rick Mann wrote:
 c) I need to declare a couple of extern structs. Can I just slap an "extern
(C)" on these and all will be well? The spec seems to indicate that this is so,
and it may be fine; I'm just looking for verification. e.g.:
 
 struct
 ControlID
 {
 	uint		signature;
 	int		id;
 };
 typedef ControlID                       HIViewID;
 extern (C)
 const HIViewID kHIViewWindowContentID;

Try this: extern extern (C) const HIViewID kHIViewWindowContentID; http://www.digitalmars.com/d/declaration.html#extern You need to add 'extern', just like in C headers. Then kHIViewWindowContentID will be a pure declaration, and the linker will look elsewhere for a definition. 'extern (C)' by itself only causes the compiler to output the symbol with C instead of D name mangling. If you link dynamically with the C lib, you are supposed to to add 'export' too, even if it works without that in some cases.
Jan 31 2007
parent reply Rick Mann <rmann-d-lang latencyzero.com> writes:
torhu Wrote:

 Try this:
 
 extern extern (C) const HIViewID kHIViewWindowContentID;
 
 http://www.digitalmars.com/d/declaration.html#extern
 
 You need to add 'extern', just like in C headers.  Then 
 kHIViewWindowContentID will be a pure declaration, and the linker will 
 look elsewhere for a definition.  'extern (C)' by itself only causes the 
 compiler to output the symbol with C instead of D name mangling.

Thank you! That worked very well. I did not interpret that section to mean I needed to add a second "extern" keyword.
 If you link dynamically with the C lib, you are supposed to to add 
 'export' too, even if it works without that in some cases.

"export" just before the rest of it, I suppose? Can you tell me how "export" changes things? It's working right now without it, and I don't see where it is in the spec...
Jan 31 2007
parent torhu <fake address.dude> writes:
Rick Mann wrote:
 torhu Wrote:
 If you link dynamically with the C lib, you are supposed to to add 
 'export' too, even if it works without that in some cases.

"export" just before the rest of it, I suppose? Can you tell me how "export" changes things? It's working right now without it, and I don't see where it is in the spec...

export is mentioned on these pages, the first two being most relevant to what you're doing: http://www.digitalmars.com/d/attribute.html http://www.digitalmars.com/d/htomodule.html http://www.digitalmars.com/d/dll.html http://www.digitalmars.com/d/windows.html I don't know much more than what's on those pages. But like I said, some variables seem to link correctly without 'export'. Which ones might depend on the compiler or linker you're using. Using 'export' means that you can't link statically to the C lib and expect things to work. Not sure what to do about that, I just use search and replace to remove export.
Jan 31 2007