Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

function returning function pointer (recursive type)

5 views
Skip to first unread message

Mark Piffer

unread,
May 14, 2009, 1:59:56 PM5/14/09
to
Hi group,
only today I stumbled over the famous (?) inability of C to define
recursive types for functions.
The task was to define a daisy chain of functions which facilitate
insertion and deletion by
passing and returning function pointers of their very own type. Each
function should hold
a static variable to its' successor. After having unwound my brain
from the infinite recursion
that happened in the first typedef (*)()(*foo)((*)(...etc. I rummaged
the comp.lang.c archives
and found the explanation with a workaround based on structs. I
remember however that
function pointers can be cast into one another and back without
invoking undefined behaviour.
Is this solution any worse than the struct thing? (code not yet
checked for logical errors, but
it compiled ok on Comeau):


typedef int (*mock_func_ptr)();
typedef mock_func_ptr (*daisychain_func_ptr)();

daisychain_func_ptr
me(daisychain_func_ptr new_func)
{
daisychain_func_ptr next;
int call_me_again;

/* do something useful here...*/

if (call_me_again) {
if (!next) {
next = (daisychain_func_ptr)new_func(0);
}
else {
next = (daisychain_func_ptr)next(new_func);
}
return (daisychain_func_ptr)me;
}
else {
if (next) {
daisychain_func_ptr t = next;
next = 0;
return (daisychain_func_ptr)t(new_func);
}
else if (new_func) {
return (daisychain_func_ptr)new_func(0);
}
else {
return 0;
}
}
}

Mark Piffer

unread,
May 14, 2009, 3:25:57 PM5/14/09
to

After having some spare minutes to think about it while driving home,
I think I can answer myself: the above IS undefined behaviour because
the function pointers are deref'd with the wrong type. I should have
noticed when I had to cast the "me" in the return statement.

luserXtrog

unread,
May 14, 2009, 9:50:27 PM5/14/09
to

I think you can avoid the undefined behavior by using void pointers
as intermediaries. I'm not sure what this is supposed to "do", but
I think the following is equivalent to your example.

HTH!

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

void * me (void *vfunc) {
static void *(*next)(void *) = NULL;
static bool again = false;
void *(*func)(void *) = vfunc;

if (again) {
return next = next?next(func):func(NULL);
} else {
if (next) {
void *(*t)(void *) = next;
next = NULL;
return t(func);
} else if (func) {
return func(NULL);
} else return NULL;
}
}

int main() {
printf("%x\n", me(NULL));
printf("%x\n", me(me));
}


--
lxt

Nate Eldredge

unread,
May 14, 2009, 10:10:18 PM5/14/09
to
luserXtrog <mij...@yahoo.com> writes:

That won't generally work. void * can't be relied on to be able to
store a function pointer.

luserXtrog

unread,
May 14, 2009, 11:00:57 PM5/14/09
to
On May 14, 9:10 pm, Nate Eldredge <n...@vulcan.lan> wrote:

The standard appears to disagree.

J.5.7 Function pointer casts
A pointer to an object or to void may be cast to a pointer to a
function, allowing data to
be invoked as a function (6.5.4).
A pointer to a function may be cast to a pointer to an object or to
void, allowing a
function to be inspected or modified (for example, by a debugger)
(6.5.4).

--
lxt

Flash Gordon

unread,
May 15, 2009, 12:59:20 AM5/15/09
to

Now read the heading of Appendix J. It is "Common Extensions". So the
standard is telling you that this is a common extension and *not*
something specifically allowed.
--
Flash Gordon

Peter Nilsson

unread,
May 15, 2009, 1:06:38 AM5/15/09
to
On May 15, 1:00 pm, luserXtrog <mijo...@yahoo.com> wrote:
> On May 14, 9:10 pm, Nate Eldredge <n...@vulcan.lan> wrote:
> > That won't generally work.  void * can't be relied on to
> > be able to store a function pointer.
>
> The standard appears to disagree.
>
> J.5.7 Function pointer casts

Annex J is non normative. J.5 is Common extensions.

--
Peter

Nate Eldredge

unread,
May 15, 2009, 1:06:56 AM5/15/09
to
luserXtrog <mij...@yahoo.com> writes:

Annex J.5 is entitled "Common extensions". These are features that some
implementations provide, but they are not required to do so.

More to the point here is 6.3.2.3 (1). "A pointer to void may be
converted to or from a pointer to any incomplete or object type."
Function types are not included, and AFAIK there is nowhere else in the
body of the Standard that allows converting a function pointer to and
from a void pointer.

Keith Thompson

unread,
May 15, 2009, 2:46:17 AM5/15/09
to
luserXtrog <mij...@yahoo.com> writes:
> On May 14, 9:10 pm, Nate Eldredge <n...@vulcan.lan> wrote:
[...]

>> That won't generally work.  void * can't be relied on to be able to
>> store a function pointer.
>
> The standard appears to disagree.
>
> J.5.7 Function pointer casts
> A pointer to an object or to void may be cast to a pointer to a
> function, allowing data to
> be invoked as a function (6.5.4).
> A pointer to a function may be cast to a pointer to an object or to
> void, allowing a
> function to be inspected or modified (for example, by a debugger)
> (6.5.4).

Section J.5 is titled "Common extensions.

I'll just assume that "The standard appears to disagree." wasn't meant
to imply that it actually does disagree.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

luserXtrog

unread,
May 15, 2009, 3:54:17 AM5/15/09
to
On May 15, 1:46 am, Keith Thompson <ks...@mib.org> wrote:

> luserXtrog <mijo...@yahoo.com> writes:
> > On May 14, 9:10 pm, Nate Eldredge <n...@vulcan.lan> wrote:
> [...]
> >> That won't generally work.  void * can't be relied on to be able to
> >> store a function pointer.
>
> > The standard appears to disagree.
>
> > J.5.7 Function pointer casts
> > A pointer to an object or to void may be cast to a pointer to a
> > function, allowing data to
> > be invoked as a function (6.5.4).
> > A pointer to a function may be cast to a pointer to an object or to
> > void, allowing a
> > function to be inspected or modified (for example, by a debugger)
> > (6.5.4).
>
> Section J.5 is titled "Common extensions.
>
> I'll just assume that "The standard appears to disagree." wasn't meant
> to imply that it actually does disagree.
>

Yes. It was the first thing I found so I rushed off to retort.
The statement was intentionally vague to reflect my lack of
certainty. Correction appreciated.

--
lxt

0 new messages