Welcome to Web-News
A Web-based News Reader
Subject Re: converting function pointers
From Russ Lewis <spamhole-2001-07-16@deming-os.org>
Date Tue, 14 Dec 2004 20:48:49 -0700
Newsgroups digitalmars.D

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.


Recent messages in this thread
 
-# converting function pointers Tyro 14-Dec-2004 12:50 pm
.-# Re: converting function pointers Russ Lewis 14-Dec-2004 01:26 pm
.|-# Re: converting function pointers John Reimer 14-Dec-2004 01:54 pm
.|.-# Re: converting function pointers John Reimer 14-Dec-2004 02:09 pm
.|.|\# Re: converting function pointers Russ Lewis 14-Dec-2004 03:15 pm
.|.-# Re: converting function pointers Russ Lewis 14-Dec-2004 03:15 pm
.|..\# Re: converting function pointers John Reimer 14-Dec-2004 04:14 pm
.|# Re: converting function pointers Tyro 14-Dec-2004 05:55 pm
.-# Re: converting function pointers John Reimer 14-Dec-2004 06:08 pm
..-# Re: converting function pointers Tyro 14-Dec-2004 06:42 pm
...|# Re: converting function pointers John Reimer 14-Dec-2004 06:52 pm
...-# Re: converting function pointers David Medlock 14-Dec-2004 07:48 pm
...|-# Re: converting function pointers Russ Lewis 14-Dec-2004 10:19 pm
...|.\# Re: converting function pointers John Reimer 15-Dec-2004 12:48 am
...-# Re: converting function pointers (Current message) Russ Lewis 14-Dec-2004 10:48 pm
....-# Re: converting function pointers Tyro 15-Dec-2004 05:34 am
....||# Re: converting function pointers David Medlock 15-Dec-2004 07:43 am
....|\# Re: converting function pointers Russ Lewis 15-Dec-2004 09:56 am
....\# Re: converting function pointers John Reimer 15-Dec-2004 10:47 am