Solved

for fun only II

Posted on 1998-08-19
18
214 Views
Last Modified: 2010-04-15
How can a function return a pointer to itself?
0
Comment
Question by:newexpert
  • 10
  • 6
  • 2
18 Comments
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
void * SomeFunc( void )
{
      return SomeFunc ;
}

You could be elegant, but this works!
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
Pity if you need to use the returned pointer you have to know what to cast it to.  Any solution without casting?
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
To avoid repetition of solution, here's what I've got a year ago:

Practical application: FSM
void *a(void) { return cond ? b : c; }
void *b(void) { return cond ? a : c; }
void *c(void) { return cond ? a : 0; }
void driver(void) { void *(*ptr)(void) = a; while (ptr=(void (*)(void))ptr()) != 0); }

This is ugly and probably not suitable for anything but IOCCC.  But unfortunately every memory efficient FSM I wrote would look something like this.
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
Hint: I wouldn't mind some clever macro expansion that can be conveniently hidden in a header file.
0
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
Well I would suggest typedef'ing a "pointer to function with these parameters" type.

IIRC the C syntax is something like

typedef void (* FUNCPTR)( void ) ;

FUNCPTR SomeFunc( void )
{
return (FUNCPTR)SomeFunc ;
}

I think you can omit the (FUNCPTR) cast on the return line in C but not C++

Your code then becomes (assuming I'm reading your brackets right)

FUNCPTR a(void) { return cond ? b : c; }
FUNCPTR b(void) { return cond ? a : c; }
FUNCPTR c(void) { return cond ? a : 0; }
void driver(void)
{
  FUNCPTR ptr = a ;
  while ( ptr != NULL )
  {
      ptr = (*ptr)(void) ;    
  }
}

0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
Watch your code again!!!  I doubt it would even pass through the compiler

typedef void (* FUNCPTR)( void ) ;

FUNCPTR ptr = /* ... */;

ptr = (*ptr)(); /* ?????? How can ptr() return a value ????? */
0
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
typedef void *(* FUNCPTR)( void ) ;

FUNCPTR a(void) ;
FUNCPTR b(void) ;
FUNCPTR c(void) { return (FUNCPTR)( cond ? a : 0 ) ; }
FUNCPTR a(void) { return (FUNCPTR)( cond ? b : c ) ; }
FUNCPTR b(void) { return (FUNCPTR)( cond ? a : c ) ; }

void driver(void)
{
  FUNCPTR ptr = (FUNCPTR)a ;
  while ( ptr != NULL )
  {
     ptr = (FUNCPTR)(*ptr)() ;
  }
 
}

0
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
Oh any of course you better define cond too
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
Yes that would work, but is the following really necessary?

FUNCPTR c(void) { return (FUNCPTR)( cond ? a : 0 ) ; }
FUNCPTR a(void) { return (FUNCPTR)( cond ? b : c ) ; }
FUNCPTR b(void) { return (FUNCPTR)( cond ? a : c ) ; }

Why not just leave it as before

void *c(void) { return cond ? a : 0; }
void *a(void) { return cond ? b : c; }
void *b(void) { return cond ? a : c; }

and it transforms to the one I found.
If I really wanted to use typedef I'd put it inside driver() so the global namespace is not polluted.

Any better suggestion?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
Use FUNCPTR (or similar) if you want to be typesafe.  In your example it doesn't really matter, but if the functions took lots of parameters it would help validate you got it right.

The casts between { } can be omitted in C, but in C++ the compiler complains without it.

I could macro the whole thing, but IMHO this is worse as it's still a global name and I hate macros because of all the numerous problems associated with them.


0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
No, C++ compilers shouldn't.  Because by definition any pointer can be implicitly converted to a void *.
0
 
LVL 2

Accepted Solution

by:
JYoungman earned 30 total points
Comment Utility
struct tagHack { struct tagHack (*fptr)(int,int,double); }
typedef struct tagHack TYPENAME;

TYPENAME the_func(int a, int b, double x)
{
      TYPENAME ret;
      /* .... */
      ret.fptr = the_func;
      return ret;
}

Obviously you can change the parameter list to whatever you want.

0
 
LVL 8

Expert Comment

by:Answers2000
Comment Utility
newexpert - it's true any ptr can convert to void *,

however we're not converting to void *, we're converting to FUNCPTR which is typedef'd
void *(* FUNCPTR)( void ) ;

If you make the returns from a, b & c into void *, then you still need casts inside driver * to go back
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
void *c(void) { return cond ? a : 0; }
void *a(void) { return cond ? b : c; }
void *b(void) { return cond ? a : c; }

The type of a is void *(*)(void), which is implicitly converted to void *.
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
As for your answer you have given before

typedef void *(* FUNCPTR)( void ) ;

FUNCPTR a(void) { return (FUNCPTR)( cond ? b : c ) ; }

FUNCPTR is the alias of type void*(*)(void)
The pointer to FSM state function is supposed to be type
FUNCPTR(*)(void), ie void *(*)(*)(void)(void).  But when you return the pointer, it was first explicitly casted to FUNCPTR, ie from void*(*)(*)(void)(void) to void *(*)(void).

void driver(void)
{
  FUNCPTR ptr = (FUNCPTR)a ;
  while ( ptr != NULL )
  {
     ptr = (FUNCPTR)(*ptr)() ;
  }
 
}

Now in the driver function ptr has type FUNCPTR, ie void *(*)(void).  When you call (*ptr)(), because of the pointer type, compiler thinks the returned data type is void* (even though FUNCPTR is actually returned) and still needs to be casted before assigning its value to ptr.

Therefore doing it your way is no simpler than just return a void* from FSM state function and let it be casted in the driver function.  It seems the cast in the driver function is inevitable.
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
Good thought.  And congratulations.
0
 
LVL 2

Expert Comment

by:JYoungman
Comment Utility
newexpert, you cannot cast a void* pointer to ANY function pointer, at least in a conforming ANSI C program.  Most compilers allow you to get away with it, but it IS illegal.

Function pointers are not "compatible" with other kinds of pointers.
0
 
LVL 1

Author Comment

by:newexpert
Comment Utility
JYoungman:  An object is a named region of storage.
A function is stored in a named region in memory.
Therefore a pointer to a function is a pointer to an object.
Any pointer to an object can be implicitly casted to void * and back without loss of information.
Therefore it is allowed to cast function pointers to void * and back and still make calls through them. (Ref The C Programming Language 2nd Ed)
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now