www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem Passing Struct to C

reply Mike Parker <aldacron gmail.com> writes:
Testing out a new binding I knocked up for a C library. One of the 
functions takes a struct by value. It looks somewhat like this:

struct S {}
struct Color
{
     float r,g,b,a;
}

extern C void function(S* s, Color color, int x, int y, in char*) draw_text;

Now, there is another function that adjusts color values when making a 
color. In C, it is sometimes used like so:

draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

When I'm calling draw_text like this on the D side, my text output is 
corrupt. I keep getting weird things like ^^P^, but in the appropriate 
color. It's consistent, no matter what string I pass, but is different 
for each color value. If I call draw_text like this:

auto color = map_color(...);
draw_text(s, color, 0, 0, "Blarg");

It works as expected. Has anyone else seen this, or know of a 
workaround? I'm going to dig through bugzilla later on and see if it's 
been reported already, but I'm curious if anyone knows of the cause off 
hand.
May 06 2011
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 May 2011 05:56:17 -0400, Mike Parker <aldacron gmail.com> wrote:

 Testing out a new binding I knocked up for a C library. One of the  
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
      float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)  
 draw_text;

 Now, there is another function that adjusts color values when making a  
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is  
 corrupt. I keep getting weird things like ^^P^, but in the appropriate  
 color. It's consistent, no matter what string I pass, but is different  
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a  
 workaround? I'm going to dig through bugzilla later on and see if it's  
 been reported already, but I'm curious if anyone knows of the cause off  
 hand.

There are two possible causes I can think of, depending on how draw_text is defined in C. 1. is it truly a function pointer? That is, does the definition look like void (*draw_text)(S* s, ...), or is it just void draw_text(S* s, ...)? 2. It's possible that the extern C (BTW, I thought it had to be extern(C)?) is only applying to the symbol name draw_text and not the function type. If you answer no to #1, then your problem is your draw_text definition in D. It should look like this: extern(C) void draw_text(S * s, Color color, int x, int y, in char *); If you answer yes to #1, then to check what type the compiler is giving to draw text, do: pragma(msg, (typeof(draw_text)).stringof); This hopefully tells you that it's extern(C), but if not, that is likely the problem. If that's not it, I have no idea ;) -Steve
May 06 2011
parent Mike Parker <aldacron gmail.com> writes:
On 5/6/2011 9:19 PM, Steven Schveighoffer wrote:
 On Fri, 06 May 2011 05:56:17 -0400, Mike Parker <aldacron gmail.com> wrote:

 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause
 off hand.

There are two possible causes I can think of, depending on how draw_text is defined in C. 1. is it truly a function pointer? That is, does the definition look like void (*draw_text)(S* s, ...), or is it just void draw_text(S* s, ...)?

It's a pointer to a function symbol in a DLL. In Derelict, all functions are pointers on the D side, since the shared libraries are loaded manually. I've bound several C libs in the same way and never encountered this before.
 2. It's possible that the extern C (BTW, I thought it had to be
 extern(C)?) is only applying to the symbol name draw_text and not the
 function type.

Yeah, that's a typo in my post. It's definitely declared as extern(C) in the source. And I checked with the pragma given below to make sure.
 If you answer no to #1, then your problem is your draw_text definition
 in D. It should look like this:

 extern(C) void draw_text(S * s, Color color, int x, int y, in char *);

 If you answer yes to #1, then to check what type the compiler is giving
 to draw text, do:

 pragma(msg, (typeof(draw_text)).stringof);

 This hopefully tells you that it's extern(C), but if not, that is likely
 the problem.

 If that's not it, I have no idea ;)

Thanks for the guesses. I don't believe any of the libraries I've bound before now have any functions that take a struct by value. If they have, I haven't had occasion to use them yet. So I wonder if this is an issue with how the compiler handles returning a value struct from a function. Could there be a difference in how it's pushed on to the stack in a D function call versus how it's expected in C? Just grasping.
May 06 2011
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-05-06 11:56, Mike Parker wrote:
 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause off
 hand.

You need to convert the string into a C string; import std.string; auto color = map_color(...); draw_text(s, color, 0, 0, "Blarg".toStringz); -- /Jacob Carlborg
May 06 2011
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 May 2011 09:16:02 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2011-05-06 11:56, Mike Parker wrote:
 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause off
 hand.

You need to convert the string into a C string; import std.string; auto color = map_color(...); draw_text(s, color, 0, 0, "Blarg".toStringz);

No, D implicitly casts string literals to zero-terminated const(char)*. That part is fine. -Steve
May 06 2011
next sibling parent Mike Parker <aldacron gmail.com> writes:
On 5/6/2011 10:23 PM, Steven Schveighoffer wrote:
 On Fri, 06 May 2011 09:16:02 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2011-05-06 11:56, Mike Parker wrote:
 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause off
 hand.

You need to convert the string into a C string; import std.string; auto color = map_color(...); draw_text(s, color, 0, 0, "Blarg".toStringz);

No, D implicitly casts string literals to zero-terminated const(char)*. That part is fine.

toStringz was actually the first thing I went for when I got the corrupted output, thinking that maybe literals were no longer null terminated. I can't for the life of me figure out what's different about passing a local struct variable and one that's returned by value from a function call. The only thing I can think of is that the temp returned from the function is somehow corrupting the stack when it's pushed for the function call. But why? I'm hoping someone can shed some light on that aspect.
May 06 2011
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-05-06 15:23, Steven Schveighoffer wrote:
 On Fri, 06 May 2011 09:16:02 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2011-05-06 11:56, Mike Parker wrote:
 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause off
 hand.

You need to convert the string into a C string; import std.string; auto color = map_color(...); draw_text(s, color, 0, 0, "Blarg".toStringz);

No, D implicitly casts string literals to zero-terminated const(char)*. That part is fine. -Steve

Since when? -- /Jacob Carlborg
May 06 2011
parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 06/05/2011 19:40, Jacob Carlborg wrote:
 No, D implicitly casts string literals to zero-terminated const(char)*.
 That part is fine.

 -Steve

Since when?

Since const was introduced, before then they implicitly casted to char* instead. And that has been the case since early D1. -- Robert http://octarineparrot.com/
May 06 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-05-06 21:05, Robert Clipsham wrote:
 On 06/05/2011 19:40, Jacob Carlborg wrote:
 No, D implicitly casts string literals to zero-terminated const(char)*.
 That part is fine.

 -Steve

Since when?

Since const was introduced, before then they implicitly casted to char* instead. And that has been the case since early D1.

I think I've heard of it but I thought that was before D1 and had been remove. -- /Jacob Carlborg
May 08 2011
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Mike Parker:

 Testing out a new binding I knocked up for a C library. One of the 
 functions takes a struct by value. It looks somewhat like this:
 
 struct S {}
 struct Color
 {
      float r,g,b,a;
 }
 
 extern C void function(S* s, Color color, int x, int y, in char*) draw_text;

My suggestion is: 1) create a test case that shows your program with minimal D code and minimal C code. 2) Create the binary 3) Disassembly it, take a look at the ASM and find the relevant parts, or show them here... Bye, bearophile
May 06 2011
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2011-05-06 11:56, Mike Parker wrote:
 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause off
 hand.

Don't know if it has anything to do with the problem but you have to watch out with the floats, they are initialized to NaN. -- /Jacob Carlborg
May 06 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 5/6/11, Jacob Carlborg <doob me.com> wrote:
 On 2011-05-06 11:56, Mike Parker wrote:
 Testing out a new binding I knocked up for a C library. One of the
 functions takes a struct by value. It looks somewhat like this:

 struct S {}
 struct Color
 {
 float r,g,b,a;
 }

 extern C void function(S* s, Color color, int x, int y, in char*)
 draw_text;

 Now, there is another function that adjusts color values when making a
 color. In C, it is sometimes used like so:

 draw_text(s, map_color(255, 0, 0, 0), 0, 0, "Blarg");

 When I'm calling draw_text like this on the D side, my text output is
 corrupt. I keep getting weird things like ^^P^, but in the appropriate
 color. It's consistent, no matter what string I pass, but is different
 for each color value. If I call draw_text like this:

 auto color = map_color(...);
 draw_text(s, color, 0, 0, "Blarg");

 It works as expected. Has anyone else seen this, or know of a
 workaround? I'm going to dig through bugzilla later on and see if it's
 been reported already, but I'm curious if anyone knows of the cause off
 hand.

Don't know if it has anything to do with the problem but you have to watch out with the floats, they are initialized to NaN. -- /Jacob Carlborg

And char arrays are initialized to 0xFF, which could be another source of problems.
May 06 2011