www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Declaring a D pointer to a C function

reply Johannes Pfau <spam example.com> writes:
=46rom a discussion related to derelict:
How do you write this:
-------------------------------------------------------
alias extern(C) int function(void* test) FTInitFunc;
FTInitFunc FT_Init_FreeType
-------------------------------------------------------
without the alias?
-------------------------------------------------------
extern(C) int function(void* test) FT_Init_FreeType;
-------------------------------------------------------
is not the same!
both are fields containing a C function pointer, but the first field
has D name mangling (_D4test16FT_Init_FreeTypePUPvZi) and the second
has C name mangling: (FT_Init_FreeType, which conflicts with the C
function FT_Init_FreeType)

And a related question from stackoverflow:
(http://stackoverflow.com/questions/6257078/casting-clutteractor-to-clutter=
stage)
How to write this:
-------------------------------------------------------
alias extern(C) void function(void*, const char*) setTitleFunc;
auto clutter_stage_set_title =3D
getSym!(setTitleFunc)("clutter_stage_set_title");
-------------------------------------------------------
without the alias?

http://d.puremagic.com/issues/show_bug.cgi?id=3D2168 and
http://d.puremagic.com/issues/show_bug.cgi?id=3D4288 seem to be related,
extern(C) seems to work almost nowhere ;-)


--=20
Johannes Pfau
Jul 12 2011
next sibling parent reply Marco Cosentino <cosentino.ma gmail.com> writes:
On 12/07/2011 11:36, Johannes Pfau wrote:
  From a discussion related to derelict:
 How do you write this:
 -------------------------------------------------------
 alias extern(C) int function(void* test) FTInitFunc;
 FTInitFunc FT_Init_FreeType
 -------------------------------------------------------
 without the alias?
 -------------------------------------------------------
 extern(C) int function(void* test) FT_Init_FreeType;
 -------------------------------------------------------
 is not the same!
 both are fields containing a C function pointer, but the first field
 has D name mangling (_D4test16FT_Init_FreeTypePUPvZi) and the second
 has C name mangling: (FT_Init_FreeType, which conflicts with the C
 function FT_Init_FreeType)

 And a related question from stackoverflow:
 (http://stackoverflow.com/questions/6257078/casting-clutteractor-to-clutterstage)
 How to write this:
 -------------------------------------------------------
 alias extern(C) void function(void*, const char*) setTitleFunc;
 auto clutter_stage_set_title =
 getSym!(setTitleFunc)("clutter_stage_set_title");
 -------------------------------------------------------
 without the alias?

 http://d.puremagic.com/issues/show_bug.cgi?id=2168 and
 http://d.puremagic.com/issues/show_bug.cgi?id=4288 seem to be related,
 extern(C) seems to work almost nowhere ;-)

You should declare the function pointer without the "extern(C)". Example: alias int function(void* test) FTInitFunc; extern(C) int foo(void* test){ .... } FTInitFunc foo_ptr = &foo; This worked for me.
Jul 12 2011
parent Marco Cosentino <cosentino.ma gmail.com> writes:
On 12/07/2011 13:15, Trass3r wrote:
 You should declare the function pointer without the "extern(C)".

 Example:
 alias int function(void* test) FTInitFunc;

 extern(C) int foo(void* test){ .... }

 FTInitFunc foo_ptr = &foo;

 This worked for me.

That's a bug.

Oh, well, I forgot to mention that the function pointer is a callback that gets called by a linked C library. IMHO I don't think that the alias definition should carry with her the informations about the calling convention. This is a convention for the caller and the callee.
Jul 12 2011
prev sibling next sibling parent Trass3r <un known.com> writes:
 You should declare the function pointer without the "extern(C)".

 Example:
 alias int function(void* test) FTInitFunc;

 extern(C) int foo(void* test){ .... }

 FTInitFunc foo_ptr = &foo;

 This worked for me.

That's a bug.
Jul 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 12 Jul 2011 05:36:15 -0400, Johannes Pfau <spam example.com> wrote:

 From a discussion related to derelict:
 How do you write this:
 -------------------------------------------------------
 alias extern(C) int function(void* test) FTInitFunc;
 FTInitFunc FT_Init_FreeType
 -------------------------------------------------------
 without the alias?
 -------------------------------------------------------
 extern(C) int function(void* test) FT_Init_FreeType;
 -------------------------------------------------------
 is not the same!
 both are fields containing a C function pointer, but the first field
 has D name mangling (_D4test16FT_Init_FreeTypePUPvZi) and the second
 has C name mangling: (FT_Init_FreeType, which conflicts with the C
 function FT_Init_FreeType)

 And a related question from stackoverflow:
 (http://stackoverflow.com/questions/6257078/casting-clutteractor-to-clutterstage)
 How to write this:
 -------------------------------------------------------
 alias extern(C) void function(void*, const char*) setTitleFunc;
 auto clutter_stage_set_title =
 getSym!(setTitleFunc)("clutter_stage_set_title");
 -------------------------------------------------------
 without the alias?

extern(C) extern(C) maybe? :) or maybe: extern(C) int function(void * test) extern(C) FT_Init_FreeType; Just some thoughts, it probably doesn't work. -Steve
Jul 12 2011
prev sibling next sibling parent Johannes Pfau <spam example.com> writes:
Steven Schveighoffer wrote:
On Tue, 12 Jul 2011 05:36:15 -0400, Johannes Pfau <spam example.com>
wrote:

 From a discussion related to derelict:
 How do you write this:
 -------------------------------------------------------
 alias extern(C) int function(void* test) FTInitFunc;
 FTInitFunc FT_Init_FreeType
 -------------------------------------------------------
 without the alias?
 -------------------------------------------------------
 extern(C) int function(void* test) FT_Init_FreeType;
 -------------------------------------------------------
 is not the same!
 both are fields containing a C function pointer, but the first field
 has D name mangling (_D4test16FT_Init_FreeTypePUPvZi) and the second
 has C name mangling: (FT_Init_FreeType, which conflicts with the C
 function FT_Init_FreeType)

 And a related question from stackoverflow:
 (http://stackoverflow.com/questions/6257078/casting-clutteractor-to-clutterstage)
 How to write this:
 -------------------------------------------------------
 alias extern(C) void function(void*, const char*) setTitleFunc;
 auto clutter_stage_set_title =
 getSym!(setTitleFunc)("clutter_stage_set_title");
 -------------------------------------------------------
 without the alias?

extern(C) extern(C) maybe? :) or maybe: extern(C) int function(void * test) extern(C) FT_Init_FreeType;

Nope, that doesn't work: --------------------------------- test.d(3): no identifier for declarator int C function(void* test) test.d(3): semicolon expected, not 'extern' test.d(3): no identifier for declarator FT_Init_FreeType --------------------------------- also, if that worked, shouldn't it be equal to this? --------------------------------- extern(C) int function(void* test) FT_Init_FreeType; --------------------------------- This works, but it's not what I want. Derelict needs a _field_, FT_Init_FreeType with D name mangling. So the usual {module}.{module}.FT_Init_FreeType in mangled form. This _field_ should contain a pointer to a extern(C) function. This code with alias does just that:
 -------------------------------------------------------
 alias extern(C) int function(void* test) FTInitFunc;
 FTInitFunc FT_Init_FreeType
 -------------------------------------------------------


functions, so the above must be accomplished without the alias. I think it should be something like this: --------------------------------- extern(C) int function(void * test) extern(D) FT_Init_FreeType; (extern(C) int function(void * test)) FT_Init_FreeType; extern(C)(int function(void * test)) FT_Init_FreeType; extern(C){int function(void * test)} FT_Init_FreeType; --------------------------------- None of these work, though.
Just some thoughts, it probably doesn't work.

-Steve

-- Johannes Pfau
Jul 12 2011
prev sibling next sibling parent Johannes Pfau <spam example.com> writes:
Trass3r wrote:
 You should declare the function pointer without the "extern(C)".

 Example:
 alias int function(void* test) FTInitFunc;

 extern(C) int foo(void* test){ .... }

 FTInitFunc foo_ptr = &foo;

 This worked for me.

That's a bug.

I agree. It looks like the above code assigns a extern(C) function pointer to a field which should only accept D function pointers. I guess if you then call foo_ptr dmd will use the D calling convention and that'll crash, at least for more complicated functions. -- Johannes Pfau
Jul 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 12 Jul 2011 09:42:22 -0400, Johannes Pfau <spam example.com> wrote:

 Steven Schveighoffer wrote:
 On Tue, 12 Jul 2011 05:36:15 -0400, Johannes Pfau <spam example.com>
 wrote:

 From a discussion related to derelict:
 How do you write this:
 -------------------------------------------------------
 alias extern(C) int function(void* test) FTInitFunc;
 FTInitFunc FT_Init_FreeType
 -------------------------------------------------------
 without the alias?
 -------------------------------------------------------
 extern(C) int function(void* test) FT_Init_FreeType;
 -------------------------------------------------------
 is not the same!
 both are fields containing a C function pointer, but the first field
 has D name mangling (_D4test16FT_Init_FreeTypePUPvZi) and the second
 has C name mangling: (FT_Init_FreeType, which conflicts with the C
 function FT_Init_FreeType)

 And a related question from stackoverflow:
 (http://stackoverflow.com/questions/6257078/casting-clutteractor-to-clutterstage)
 How to write this:
 -------------------------------------------------------
 alias extern(C) void function(void*, const char*) setTitleFunc;
 auto clutter_stage_set_title =
 getSym!(setTitleFunc)("clutter_stage_set_title");
 -------------------------------------------------------
 without the alias?

extern(C) extern(C) maybe? :) or maybe: extern(C) int function(void * test) extern(C) FT_Init_FreeType;

Nope, that doesn't work: --------------------------------- test.d(3): no identifier for declarator int C function(void* test) test.d(3): semicolon expected, not 'extern' test.d(3): no identifier for declarator FT_Init_FreeType --------------------------------- also, if that worked, shouldn't it be equal to this? --------------------------------- extern(C) int function(void* test) FT_Init_FreeType; --------------------------------- This works, but it's not what I want. Derelict needs a _field_, FT_Init_FreeType with D name mangling. So the usual {module}.{module}.FT_Init_FreeType in mangled form. This _field_ should contain a pointer to a extern(C) function.

Oh, I misread which one did which. I thought it was the opposite. Hm... so extern(C) affects both the function pointer type and the name mangling. Interesting. But wait, don't normal D functions have C calling convention? I thought that was one of the benefits of D's ABI? -Steve
Jul 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 12 Jul 2011 09:53:28 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 But wait, don't normal D functions have C calling convention?  I thought  
 that was one of the benefits of D's ABI?

Tested it out, definitely is different. So this clearly needs to be addressed. -Steve
Jul 12 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I just had a bug where a D function is implicitly converted to an
extern(C) function pointer.

I've had this definition:
alias extern (C) void function(void* userData) PaStreamFinishedCallback;

And this extern(C) function:
PaError  Pa_SetStreamFinishedCallback(PaStream* stream,
PaStreamFinishedCallback streamFinishedCallback);

And I used this callback:
void StreamFinished(void* userData)
{
    auto localData = cast(TestData*)userData;
    writefln("Stream Completed: %s", localData.message);
}

// this is where the binding takes place
void main() { ...; SetStreamFinishedCallback(..., &StreamFinished); }

That code is invalid. The fix is to add extern(C) to my callback:
extern(C) void StreamFinished(void* userData)

Is this going to be fixed any time soon? Allowing callbacks with D
calling convention where a C callback is expected should be an error,
and this is like the 10th time I've ran into this bug.
Jul 12 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message 
news:mailman.1569.1310506439.14074.digitalmars-d-learn puremagic.com...
 Is this going to be fixed any time soon? Allowing callbacks with D
 calling convention where a C callback is expected should be an error,
 and this is like the 10th time I've ran into this bug.

What, the bug that annoyed me so much I fixed it myself? Yeah, this should be gone by the next release.
Jul 13 2011
prev sibling next sibling parent Trass3r <un known.com> writes:
 Is this going to be fixed any time soon? Allowing callbacks with D
 calling convention where a C callback is expected should be an error,
 and this is like the 10th time I've ran into this bug.

http://d.puremagic.com/issues/show_bug.cgi?id=3797
Jul 12 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 7/12/11, Trass3r <un known.com> wrote:
 Is this going to be fixed any time soon? Allowing callbacks with D
 calling convention where a C callback is expected should be an error,
 and this is like the 10th time I've ran into this bug.

http://d.puremagic.com/issues/show_bug.cgi?id=3797

Jul 12 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Oh there's a pull already, this is great.
https://github.com/D-Programming-Language/dmd/pull/96
Jul 12 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 7/13/11, Daniel Murphy <yebblies nospamgmail.com> wrote:
 "Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message
 news:mailman.1569.1310506439.14074.digitalmars-d-learn puremagic.com...
 Is this going to be fixed any time soon? Allowing callbacks with D
 calling convention where a C callback is expected should be an error,
 and this is like the 10th time I've ran into this bug.

What, the bug that annoyed me so much I fixed it myself? Yeah, this should be gone by the next release.

Thanks! I've literally lost an entire day once when I was just starting using D and C together and had a calling convention mismatch. :x
Jul 13 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message 
news:mailman.1607.1310570915.14074.digitalmars-d-learn puremagic.com...
 Thanks! I've literally lost an entire day once when I was just
 starting using D and C together and had a calling convention mismatch.
 :x

It's worse than just calling conventions - try changing the parameter types! (or basically anything except the return type)
Jul 13 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 13 Jul 2011 11:32:50 -0400, Daniel Murphy  
<yebblies nospamgmail.com> wrote:

 "Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message
 news:mailman.1607.1310570915.14074.digitalmars-d-learn puremagic.com...
 Thanks! I've literally lost an entire day once when I was just
 starting using D and C together and had a calling convention mismatch.
 :x

It's worse than just calling conventions - try changing the parameter types! (or basically anything except the return type)

Yeah, examining the assembly, a major difference is that D passes one parameter in a register, whereas C pushes it on the stack. This means you are going to have off-by-one corruption any time you access a parameter. -Steve
Jul 13 2011