• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 224
  • Last Modified:

for fun only II

How can a function return a pointer to itself?
0
newexpert
Asked:
newexpert
  • 10
  • 6
  • 2
1 Solution
 
Answers2000Commented:
void * SomeFunc( void )
{
      return SomeFunc ;
}

You could be elegant, but this works!
0
 
newexpertAuthor Commented:
Pity if you need to use the returned pointer you have to know what to cast it to.  Any solution without casting?
0
 
newexpertAuthor Commented:
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
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
newexpertAuthor Commented:
Hint: I wouldn't mind some clever macro expansion that can be conveniently hidden in a header file.
0
 
Answers2000Commented:
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
 
newexpertAuthor Commented:
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
 
Answers2000Commented:
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
 
Answers2000Commented:
Oh any of course you better define cond too
0
 
newexpertAuthor Commented:
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
 
Answers2000Commented:
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
 
newexpertAuthor Commented:
No, C++ compilers shouldn't.  Because by definition any pointer can be implicitly converted to a void *.
0
 
JYoungmanCommented:
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
 
Answers2000Commented:
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
 
newexpertAuthor Commented:
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
 
newexpertAuthor Commented:
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
 
newexpertAuthor Commented:
Good thought.  And congratulations.
0
 
JYoungmanCommented:
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
 
newexpertAuthor Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

  • 10
  • 6
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now