digitalmars.D - converting function pointers
- Tyro (16/16) Dec 14 2004 How does one convert a C function pointer D?
- Russ Lewis (6/18) Dec 14 2004 I ran a little testcase, and was surprised to find that you can't just
- John Reimer (35/62) Dec 14 2004 Actually, it's entirely possible to use the function pointers directly.
- John Reimer (5/5) Dec 14 2004 I should add that the great thing about being able to assign a extern(C)...
- Russ Lewis (2/6) Dec 14 2004 Indeed.
- Russ Lewis (5/9) Dec 14 2004 Y'know, that's exactly what I tried at first, but I did it inside a
- John Reimer (11/25) Dec 14 2004 Yeah, I did try that too... but hadn't thought there was a solution
- Tyro (3/29) Dec 14 2004 John & Russ, thank you both very much for your assistance on this.
- John Reimer (17/43) Dec 14 2004 I just realized that you probably weren't talking about extern(C)
- Tyro (15/64) Dec 14 2004 Actually I just came home and didn't get a chance to read your responses...
- John Reimer (11/24) Dec 14 2004 He, he. Well, I'd love to be a purist too, but I'm not yet up to the
- David Medlock (11/24) Dec 14 2004 Does your examples cover say OpenGL extensions which must be acquired
- Russ Lewis (14/18) Dec 14 2004 I took a quick look at the link, and I think that there should be no
- John Reimer (20/51) Dec 14 2004 It's very likely that these would have to be declared extern(Windows) to...
- Russ Lewis (95/109) Dec 14 2004 Well, I'm not sure from what you wrote whether you already know all that...
- Tyro (8/29) Dec 15 2004 Immensely! Russ, your coverage of the topic was exceptional and greatly
- David Medlock (7/20) Dec 15 2004 Or perhaps use *function* as pointers to C functions, and delegates
- Russ Lewis (5/8) Dec 15 2004 For most applications, I would agree. But, since one of the goals of D
- John Reimer (3/4) Dec 15 2004 I must admit, that was a very good description!
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
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
Russ Lewis wrote:Tyro 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. Here's an example: Outputs: 2, c 2, c Hope that helps, JohnHow 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
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
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
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
Russ Lewis wrote:John Reimer wrote: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 :-( - JohnActually, 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
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, AndrewJohn & Russ, thank you both very much for your assistance on this. Andrew
Dec 14 2004
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, AndrewI 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
John Reimer 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. Cheers, AndrewHow 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, AndrewI 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
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! :-DTo 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
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
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.aspI 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
Russ Lewis wrote:David Medlock wrote: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().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.aspI 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.)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
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
Russ Lewis wrote:Tyro wrote:[ some great information ]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.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
Tyro wrote:Russ Lewis wrote: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.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
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
Russ Lewis wrote:Hope all this helps.I must admit, that was a very good description! - John
Dec 15 2004