Solved

for fun only II

Posted on 1998-08-19
18
217 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
Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

 
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 30 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

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

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

This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
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.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

803 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