View mode: basic / threaded / horizontal-split · Log in · Help
May 06, 2011
Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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
Re: Problem Passing Struct to C
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/
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home