Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

for fun only II

Posted on 1998-08-19
18
Medium Priority
?
223 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
ID: 1252155
void * SomeFunc( void )
{
      return SomeFunc ;
}

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

Author Comment

by:newexpert
ID: 1252156
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
ID: 1252157
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 1

Author Comment

by:newexpert
ID: 1252158
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
ID: 1252159
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
ID: 1252160
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
ID: 1252161
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
ID: 1252162
Oh any of course you better define cond too
0
 
LVL 1

Author Comment

by:newexpert
ID: 1252163
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
 
LVL 8

Expert Comment

by:Answers2000
ID: 1252164
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
ID: 1252165
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 120 total points
ID: 1252166
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
ID: 1252167
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
ID: 1252168
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
ID: 1252169
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
ID: 1252170
Good thought.  And congratulations.
0
 
LVL 2

Expert Comment

by:JYoungman
ID: 1252171
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
ID: 1252172
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

773 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