Solved

for fun only II

Posted on 1998-08-19
18
216 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
 
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
What is SQL Server and how does it work?

The purpose of this paper is to provide you background on SQL Server. It’s your self-study guide for learning fundamentals. It includes both the history of SQL and its technical basics. Concepts and definitions will form the solid foundation of your future DBA expertise.

 
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

Free camera licenses with purchase of My Cloud NAS

Milestone Arcus software is compatible with thousands of industry-leading cameras for added flexibility. Upon installation on your My Cloud NAS, you will receive two (2) camera licenses already enabled in the software. And for a limited time, get additional camera licenses FREE.

Question has a verified solution.

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

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
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…
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 switch statements in the C programming language.

896 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

17 Experts available now in Live!

Get 1:1 Help Now