www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - converting function pointers

reply Tyro <Tyro_member pathlink.com> writes:
How does one convert a C function pointer D?

int   (*u.sfree) ();
void* (*salloc)  ();

int u.sfree(arg1, arg2, arg3)
{ /* do something meaningful */ }

void* salloc(arg1, arg2)
{ /* implementation implementation */ }

==========================
Does this suffice?

int deligate () free;
void* delegate () alloc;

free  = &u.sfree;
alloc = &salloc;

or is there something more that I'm missing?

Thanks,
Andrew
Dec 14 2004
next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Tyro wrote:
 How does one convert a C function pointer D?

I ran a little testcase, and was surprised to find that you can't just take the address of an extern(C) function and save it in a function pointer. (Is this a calling convention problem, or something?) However, it's easy enough to define a trivial wrapper which allows you to call the extern(C) function. Here's example code:
 import std.stdio;
  
 extern(C) void foo(int i,char c) { writef("%d, %s\n", i,c); }
  
 void main() {
   void function(int,char) fp = function void(int i,char c) { return foo(i,c);
};
   void delegate(int,char) dg = delegate void(int i,char c) { return foo(i,c);
};
  
   fp(1,'a');
   dg(2,'b');
 }

Dec 14 2004
parent reply John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 Tyro wrote:
 
 How does one convert a C function pointer D?

I ran a little testcase, and was surprised to find that you can't just take the address of an extern(C) function and save it in a function pointer. (Is this a calling convention problem, or something?) However, it's easy enough to define a trivial wrapper which allows you to call the extern(C) function. Here's example code:
 import std.stdio;
  
 extern(C) void foo(int i,char c) { writef("%d, %s\n", i,c); }
  
 void main() {
   void function(int,char) fp = function void(int i,char c) { return 
 foo(i,c); };
   void delegate(int,char) dg = delegate void(int i,char c) { return 
 foo(i,c); };
  
   fp(1,'a');
   dg(2,'b');
 }


Actually, it's entirely possible to use the function pointers directly. It probably comes down to appropriate use of the extern(C) for compatible assignment of function pointers to functions. You can also assign a function to a class function variable. Here's an example: # import std.stdio; # # extern (C) void foo1(int i, char c) # { # writefln("%d, %s", i,c); # } # # class Class # { # this() { this.foo = &foo1; } # # extern (C) void function(int,char) foo; # } # # extern(C) void function(int, char) func; # # void main() # { # Class A = new Class; # func = &foo1; # # func(2, 'c'); # A.foo(2, 'c'); # } Outputs: 2, c 2, c Hope that helps, John
Dec 14 2004
next sibling parent reply John Reimer <brk_6502 yahoo.com> writes:
I should add that the great thing about being able to assign a extern(C) 
function to a class function variable is that you can directly interface 
with C functions from toolkits and make them look like class methods. 
It really beats the idea of a function wrapper, I think.

- John
Dec 14 2004
parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
John Reimer wrote:
 I should add that the great thing about being able to assign a extern(C) 
 function to a class function variable is that you can directly interface 
 with C functions from toolkits and make them look like class methods. It 
 really beats the idea of a function wrapper, I think.

Indeed.
Dec 14 2004
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
John Reimer wrote:
 Actually, it's entirely possible to use the function pointers directly. 
  It probably comes down to appropriate use of the extern(C) for 
 compatible assignment of function pointers to functions.  You can also 
 assign a function to a class function variable.

Y'know, that's exactly what I tried at first, but I did it inside a function body (as a local variable). That didn't work, but doing it as a global did. (I'm assuming you've tried this already in a class?) I'll write this up as a bug in the other NG.
Dec 14 2004
parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 John Reimer wrote:
 
 Actually, it's entirely possible to use the function pointers 
 directly.  It probably comes down to appropriate use of the extern(C) 
 for compatible assignment of function pointers to functions.  You can 
 also assign a function to a class function variable.

Y'know, that's exactly what I tried at first, but I did it inside a function body (as a local variable). That didn't work, but doing it as a global did. (I'm assuming you've tried this already in a class?) I'll write this up as a bug in the other NG.

Yeah, I did try that too... but hadn't thought there was a solution until you mentioned it; then I got the idea that I gave in answer to your bug forum post. Yes, declaring extern(C) inside a class works fine. Although, I found that you should only declare /variables/ extern(C) in a class (not functions). You can declare functions extern(C) also, but you'll never get your program linked because the name resolution will prepend the class name to the function name to create the fully qualified name for your function... one that doesn't won't be reachable :-( - John
Dec 14 2004
prev sibling next sibling parent Tyro <ridimz_at yahoo.dot.com> writes:
Tyro wrote:
 How does one convert a C function pointer D?
 
 int   (*u.sfree) ();
 void* (*salloc)  ();
 
 int u.sfree(arg1, arg2, arg3)
 { /* do something meaningful */ }
 
 void* salloc(arg1, arg2)
 { /* implementation implementation */ }
 
 ==========================
 Does this suffice?
 
 int deligate () free;
 void* delegate () alloc;
 
 free  = &u.sfree;
 alloc = &salloc;
 
 or is there something more that I'm missing?
 
 Thanks,
 Andrew
 
 

John & Russ, thank you both very much for your assistance on this. Andrew
Dec 14 2004
prev sibling parent reply John Reimer <brk_6502 yahoo.com> writes:
Tyro wrote:
 How does one convert a C function pointer D?
 
 int   (*u.sfree) ();
 void* (*salloc)  ();
 
 int u.sfree(arg1, arg2, arg3)
 { /* do something meaningful */ }
 
 void* salloc(arg1, arg2)
 { /* implementation implementation */ }
 
 ==========================
 Does this suffice?
 
 int deligate () free;
 void* delegate () alloc;
 
 free  = &u.sfree;
 alloc = &salloc;
 
 or is there something more that I'm missing?
 
 Thanks,
 Andrew
 
 

I just realized that you probably weren't talking about extern(C) functions. Russ and I got off on a tangent on that one. You are probably just querying about the difference about C function pointers and D function pointers. I guess the main difference then is that D just uses the "function" keyword (no need for extern(C) except in some specialized situations as Russ and I were talking about) instead of C's (*)() format. delegates are along the same lines but are used for a slightly different purpose in D. Their usefulness pertains more to object oriented programming and class methods... although they have similar uses to D's function attribute; in fact they seem to be interchangeable in some respects. The docs define some of the important differences for where either can be used. I think Walter has been considering merging function and delegate syntaxes for quite awhile. Later, John
Dec 14 2004
parent reply Tyro <ridimz_at yahoo.dot.com> writes:
John Reimer wrote:
 Tyro wrote:
 
 How does one convert a C function pointer D?

 int   (*u.sfree) ();
 void* (*salloc)  ();

 int u.sfree(arg1, arg2, arg3)
 { /* do something meaningful */ }

 void* salloc(arg1, arg2)
 { /* implementation implementation */ }

 ==========================
 Does this suffice?

 int deligate () free;
 void* delegate () alloc;

 free  = &u.sfree;
 alloc = &salloc;

 or is there something more that I'm missing?

 Thanks,
 Andrew

I just realized that you probably weren't talking about extern(C) functions. Russ and I got off on a tangent on that one. You are probably just querying about the difference about C function pointers and D function pointers. I guess the main difference then is that D just uses the "function" keyword (no need for extern(C) except in some specialized situations as Russ and I were talking about) instead of C's (*)() format. delegates are along the same lines but are used for a slightly different purpose in D. Their usefulness pertains more to object oriented programming and class methods... although they have similar uses to D's function attribute; in fact they seem to be interchangeable in some respects. The docs define some of the important differences for where either can be used. I think Walter has been considering merging function and delegate syntaxes for quite awhile. Later, John

Actually I just came home and didn't get a chance to read your responses as yet. I just did a quick scan to see who had responded to my post and gave thanks where it was due. I am a purist, so I believe that D programs should be written in D. Maybe at the onset (just to get some functionality that is not yet available in the language) we can wrap up C functions for use in our programs until the "D-way" is devised. Then those functions should be reimplemented in accordance with the way things are done in D. To this end I was simply wondering how C function pointers differ from D function pointers (as you stated above) and the proper way to "D"-up a function pointer or delegate to accomplish the same thing the C function pointer would. Cheers, Andrew
Dec 14 2004
next sibling parent John Reimer <brk_6502 yahoo.com> writes:
Tyro wrote:
 
 Actually I just came home and didn't get a chance to read your responses 
 as yet. I just did a quick scan to see who had responded to my post and 
 gave thanks where it was due.

Oh, okay. :-)
 I am a purist, so I believe that D programs should be written in D. 
 Maybe at the onset (just to get some functionality that is not yet 
 available in the language) we can wrap up C functions for use in our 
 programs until the "D-way" is devised. Then those functions should be 
 reimplemented in accordance with the way things are done in D.

He, he. Well, I'd love to be a purist too, but I'm not yet up to the task of reimplementing the whole windows API, Linux API, OpenGL, SDL, etc. As long as those are around, we'll need some extern(C)'s to get things going at the lowest levels. A new OS would be nice, though, with strictly D calling convention! Now wouldn't that be Utopia! :-D
 To this end I was simply wondering how C function pointers differ from D 
 function pointers (as you stated above) and the proper way to "D"-up a 
 function pointer or delegate to accomplish the same thing the C function 
 pointer would.

Righto. I'm sure there's room for more discussion on this still. The function and delegate keywords are really fun tools in the D arsenal. Glad to help, John
Dec 14 2004
prev sibling next sibling parent reply David Medlock <amedlock nospam.org> writes:
Does your examples cover say OpenGL extensions which must be acquired 
through wgl (Windows API for OpenGL) then casted to a function pointer?

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/ntopnglr_6yer.asp

I have run into this issue also with glfw, which is a library which
hides the Windows specifics API.  It allows you to register callback 
functions which need C calling conventions.

New libraries should be done 'right' in D, but the lure of C is its 
access to low-level hardware and OS features.

My $.02
-Ash

<snip>
 I am a purist, so I believe that D programs should be written in D. 
 Maybe at the onset (just to get some functionality that is not yet 
 available in the language) we can wrap up C functions for use in our 
 programs until the "D-way" is devised. Then those functions should be 
 reimplemented in accordance with the way things are done in D.
 
 To this end I was simply wondering how C function pointers differ from D 
 function pointers (as you stated above) and the proper way to "D"-up a 
 function pointer or delegate to accomplish the same thing the C function 
 pointer would.
 
 Cheers,
 Andrew

Dec 14 2004
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
David Medlock wrote:
 Does your examples cover say OpenGL extensions which must be acquired 
 through wgl (Windows API for OpenGL) then casted to a function pointer?
 
 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/open
l/ntopnglr_6yer.asp 

I took a quick look at the link, and I think that there should be no problem whatsoever. You should be able to do something like this: NOTE: I haven't done careful analysis to make sure that LPCSTR is really a 'char*', so this is just a rough sketch: extern(C) void *wglGetProcAddress(char*); extern(C) int function() glFunctionIWantToUse = cast(extern(C) int function()) wglGetProcAddress("glFunctionIWantToUse"); This discussion has resulted in us discovering a couple of bugs with how dmd handles extern(C) function pointers, so I suspect that the compiler will (right now) choke on the cast above. But I think that this should work, once the bugs are cleared up. (I hope that I'm right, and that Walter consideres them bugs.)
Dec 14 2004
parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:
 David Medlock wrote:
 
 Does your examples cover say OpenGL extensions which must be acquired 
 through wgl (Windows API for OpenGL) then casted to a function pointer?

 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/open
l/ntopnglr_6yer.asp 

I took a quick look at the link, and I think that there should be no problem whatsoever. You should be able to do something like this: NOTE: I haven't done careful analysis to make sure that LPCSTR is really a 'char*', so this is just a rough sketch: extern(C) void *wglGetProcAddress(char*); extern(C) int function() glFunctionIWantToUse = cast(extern(C) int function()) wglGetProcAddress("glFunctionIWantToUse");

It's very likely that these would have to be declared extern(Windows) to account for the WINAPI calling convention. But your example gives the general idea. The Derelict project does this already... So does Kris' Mango.icu. People can browse both of these projects over at www.dsource.org to see how it's done in a real world situation. Both access Win32 LoadLibrary() and GetProcAddress() calls to fill function pointers similar to the way you've done it above. Mango.icu uses a little more structured approach to do the same thing: primarily it casts the function pointers to void* type before assigning the result from GetProcAddress().
 
 This discussion has resulted in us discovering a couple of bugs with how 
 dmd handles extern(C) function pointers, so I suspect that the compiler 
 will (right now) choke on the cast above.  But I think that this should 
 work, once the bugs are cleared up.  (I hope that I'm right, and that 
 Walter consideres them bugs.)
 

I'm not so sure that they are bugs, per se. They do appear to be severe short-comings. I believe the compiler has just severely limited where and when extern(...) can be used. I readily admit that it would be /really/ nice to use the extern(...) decoration in places like function literals, nested functions, non-static class members, and so on; but I'm not sure how technically feasible it is. Like you, I hope Walter can fix it or clarify the extent of the problem. Later, John
Dec 14 2004
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Tyro wrote:
 Actually I just came home and didn't get a chance to read your responses 
 as yet. I just did a quick scan to see who had responded to my post and 
 gave thanks where it was due.
 
 I am a purist, so I believe that D programs should be written in D. 
 Maybe at the onset (just to get some functionality that is not yet 
 available in the language) we can wrap up C functions for use in our 
 programs until the "D-way" is devised. Then those functions should be 
 reimplemented in accordance with the way things are done in D.
 
 To this end I was simply wondering how C function pointers differ from D 
 function pointers (as you stated above) and the proper way to "D"-up a 
 function pointer or delegate to accomplish the same thing the C function 
 pointer would.

Well, I'm not sure from what you wrote whether you already know all that you want to know. So, since I like to expound on these things, and since (maybe) you want to know more, here's a more technical explanation: The first thing to remember is that C function pointers are simply pointers to some address in memory. They contain, in their type data, information about the arguments and the return type, but at runtime, they are just a pointer like any other pointer. You can cast a function pointer to a void* and then get the address of the function in memory, for example. Likewise, you can cast a void* back to a function pointer. D function pointers are the same thing. They are a simple, single pointer. When you call a function pointer in either language, the code puts your arguments (if any) onto the stack, and then makes a subroutine call to whatever address is stored in the function pointer. The only difference between D and C function pointers is that (in some architectures) the calling convention may be different. There are various assumptions made by each language (who saves copies of registers, who cleans up the stack, the order of arguments on the stack, etc.) which may vary from language to language. The point of extern(C) is to inform the D compiler that it is talking to a C function, and so it must talk like a C function. This may be different than D's conventions. This is why you can't store a pointer to a D function in an extern(C) function pointer, or vice-versa. If the function pointer is declared extern(C), then you are saying that the compiler should use C calling conventions when it calls the function. If it is actually a D function, then things will break. To solve this, you implement a trivial wrapper function, which calls the function pointer. It serves as an interpreter between the D function and the C function. You can use wrappers in either direction; to store a pointer to a C function in a D function pointer, then create a D wrapper which calls the C function; the opposite also works. Delegates are another beast. They are a bit of a conceptual jump, but once you get used to them you'll never want to go back. Delegates are actually two pointers stored in a single variable. One of the pointers is a function pointer to a D function; the other is a void*. When you call a delegate, it passes the void* as the implicit first argument. This is exactly like how class member functions are called. Think about how a class member function works. Look at this example: class Foo { int val; int foo() { return val; } } int bar(Foo f) { return f.val; } The functions Foo.foo() and bar(Foo) are pretty much the same function. The class member function has an implicit argument (Foo) which is automatically passed when you call the member. So the code below, which calls the two functions, is almost identical when you get down to the bare metal: Foo f = new Foo; ... int x = f.foo(); int y = bar(f); Delegates work the same way. They just carry around the "this" pointer hidden inside the delegate. So this delegate: int delegate() dg = *f.foo; is pretty much the same thing as this struct: struct my_delegate { int function(void*) func; void *ptr; }; my_delegate my_dg; my_dg.func = cast(int function(void*))&bar; my_dg.ptr = cast(void*)f; And calling the delegate: int a = dg(); is just like calling the function pointer with the stored argument: int b = my_dg.func(my_dg.ptr); I would highly recommend that, in your D programs, you always use a delegate any time that you might think about using a function pointer. They are far more flexible; if you ever, in the future, decide that you needed a delegate, they are there. You can always write a wrapper function which turns a function into a delegate: int myFunc(); int delegate() dg = &myFunc(); /* syntax error, can't save funcptr in a delegate */ int delegate() dg = delegate int() { return myFunc(); } /* ok! */ (Technically, you've created a stack delegate above. The 'ptr' of the delegate is actually a pointer to the current stack frame...but since we don't ever use any stack variables, we don't care about the fact that the stack frame isn't valid later on.) The only complexity here is that if you have a function pointer variable and you have to turn it into a delegate. Then you have to write a tiny struct, and take a delegate from a member function of that struct: int delegate() ConvertFuncPtrToDelegate(int function() func) { struct Storer { int function() func; int Call() { return func(); } }; Storer *temp = new Storer[1]; temp.func = func; return &temp.Call(); } Hope all this helps.
Dec 14 2004
next sibling parent reply Tyro <ridimz_at yahoo.dot.com> writes:
Russ Lewis wrote:
 Tyro wrote:
 
 Actually I just came home and didn't get a chance to read your 
 responses as yet. I just did a quick scan to see who had responded to 
 my post and gave thanks where it was due.

 I am a purist, so I believe that D programs should be written in D. 
 Maybe at the onset (just to get some functionality that is not yet 
 available in the language) we can wrap up C functions for use in our 
 programs until the "D-way" is devised. Then those functions should be 
 reimplemented in accordance with the way things are done in D.

 To this end I was simply wondering how C function pointers differ from 
 D function pointers (as you stated above) and the proper way to "D"-up 
 a function pointer or delegate to accomplish the same thing the C 
 function pointer would.


[ some great information ]
 
 Hope all this helps.
 

Immensely! Russ, your coverage of the topic was exceptional and greatly appreciated. My question is now answered. Seems to me though that the mere existence of delegates obviates the need for function pointers in D. I would say that a merger of the two is warranted. Andrew
Dec 15 2004
next sibling parent David Medlock <amedlock nospam.org> writes:
Tyro wrote:
 Russ Lewis wrote:
 Hope all this helps.

Immensely! Russ, your coverage of the topic was exceptional and greatly appreciated. My question is now answered. Seems to me though that the mere existence of delegates obviates the need for function pointers in D. I would say that a merger of the two is warranted. Andrew

Or perhaps use *function* as pointers to C functions, and delegates always have D linkage? Delegates have a pointer + a stack frame, so if the stack frame is 0, then its a pointer to a regular function? Just a thought. Walter, we really need a way to call passed C function pointers even if it is through a pragma or other compiler-specific way.
Dec 15 2004
prev sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Tyro wrote:
 Seems to me though that the mere existence of delegates obviates the 
 need for function pointers in D. I would say that a merger of the two is 
 warranted.

For most applications, I would agree. But, since one of the goals of D "systems programming" (kernel design), I'm not sure that we want to get rid of function pointers altogether. It's nice to have a smaller, more efficient type.
Dec 15 2004
prev sibling parent John Reimer <brk_6502 yahoo.com> writes:
Russ Lewis wrote:

 Hope all this helps.

I must admit, that was a very good description! - John
Dec 15 2004