[net.lang.c] How do I declare...

roman@persci.UUCP (08/21/85)

Either I'm missing the perfectly obvious or I've found something
that's impossible to declare in C, even though it makes sense.  I'm
trying to implement a simple finite state machine with states
represented by C functions.  Each state function would accept some
input value as an argument and return a pointer to the function
implementing the next state, something like this:

STATE_FUNC (*state)(),   /* the current state         */
           *state_1(),   /* a function for each state */
            ... ,
           *state_n();

   for (;;) {
      state = (*state)(get_input());
   }

But how is STATE_FUNC typedef'ed?  It's a pointer to a function which
returns a pointer to a function which returns a pointer...  Any
suggestions?

Obviously, there are other ways to implement a finite state machine,
and I have already chosen one.  Yet this one is conceptually clean, and
it seems that there must be some way to do it; plus, this could turn
out to be a more interesting discussion than i++ vs. i = i + 1...

-- 
Bill Roman	{ihnp4,decvax,allegra,...}!uw-beaver!tikal!persci!roman

Summation, Inc, (formerly Personal Scientific Corporation)
18702 142nd Ave NE
Woodinville, WA 98072
(206) 486-0991

throopw@rtp47.UUCP (Wayne Throop) (08/23/85)

> Either I'm missing the perfectly obvious or I've found something
> that's impossible to declare in C, even though it makes sense.

You have discovered a fundamental flaw in C type notation.  In essence,
C allows recursive types only in structs, unions, and enums (and I'm not
sure how it would be usefull in enums, so that one can be ruled out for
practical purposes).

Thus, if you want an array of pointers to arrays of pointers, you can't
do it.  Nor can you declare functions returning pointers to functions.
It would be nice to be able to declare a recursive type, like so:

    typedef foo_type (*foo_type)();
    ...
    foo_type foo;
    ...
    foo = (*foo)();

but this just doesn't work (on any compiler I ever heard of).  You can
do something like

    typedef struct foo_struct{ struct foo_struct (*dummy)(); } foo_type;
    ...
    foo_type foo;
    ...
    foo.dummy = (*foo.dummy)();

Another method is less portable but slightly more appealing (in terms of
what is written to declare and use the recursive type).  That is to use
a cast at the appropriate points:

    typedef int (*foo_base_type)();
    typedef foo_base_type (*foo_type)();
    ...
    foo_type foo;
    ...
    foo = (foo_type)(*foo)();

which will fail if your compiler can't cast
pointers-to-functions-returning-int into
pointers-to-functions-returning-pointers-to-functions-returning-int,
which doesn't seem very likely.

In any event, all of these solutions are less pleasing than the
possible alternatives that would exist if only fully recursive type
declaractions were available in C.
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!rtp47!throopw

kdmoen@watcgl.UUCP (Doug Moen) (08/24/85)

In article <368@persci.UUCP> roman@persci.UUCP writes:
>Either I'm missing the perfectly obvious or I've found something
>that's impossible to declare in C, even though it makes sense.  I'm
>trying to implement a simple finite state machine with states
>represented by C functions.  Each state function would accept some
>input value as an argument and return a pointer to the function
>implementing the next state, something like this:
>
>STATE_FUNC (*state)(),   /* the current state         */
>           *state_1(),   /* a function for each state */
>            ... ,
>           *state_n();
>
>   for (;;) {
>      state = (*state)(get_input());
>   }
>
>But how is STATE_FUNC typedef'ed?  It's a pointer to a function which
>returns a pointer to a function which returns a pointer...  Any
>suggestions?

You aren't missing the perfectly obvious.
Yes, it is impossible to declare in C, even though it makes sense.

What you want is a recursive typedef:
	typedef STATE_FUNC (*STATE_FUNC)();
except that this isn't allowed.

What you will have to do instead is a kludge:
	typedef char* (*STATE_FUNC)();

	for (;;) {
		/* Note the cast: */
		state = (STATE_FUNC) (*state)(get_input());
	}
-- 
Doug Moen (watmath!watcgl!kdmoen)
University of Waterloo Computer Graphics Lab

eppstein@columbia.UUCP (David Eppstein) (08/25/85)

In article <368@persci.UUCP> roman@persci.UUCP writes:
> Either I'm missing the perfectly obvious or I've found something
> that's impossible to declare in C, even though it makes sense.  I'm
> trying to implement a simple finite state machine with states
> represented by C functions.  Each state function would accept some
> input value as an argument and return a pointer to the function
> implementing the next state...

It works if you imbed them in a struct.  Kind of ugly though.

arnold@gatech.CSNET (Arnold Robbins) (08/25/85)

In article <159@rtp47.UUCP>, throopw@rtp47.UUCP (Wayne Throop) writes:
> [....]  Nor can you declare functions returning pointers to functions. [...]

I couldn't let this one go. Take a look at /usr/include/signal.h:

int	(*signal())();

This is a function returning a pointer to a function returning integer.
The casts for SIG_IGN and friends are also interesting:

#define	SIG_DFL		(int (*)())0
#define	SIG_IGN		(int (*)())1
#define	SIG_CATCH	(int (*)())2
#define	SIG_HOLD	(int (*)())3

'Nuf said.
-- 
Arnold Robbins
CSNET:	arnold@gatech	ARPA:	arnold%gatech.csnet@csnet-relay.arpa
UUCP:	{ akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold

Hello. You have reached the Coalition to Eliminate Answering Machines.
Unfortunately, no one can come to the phone right now....

joemu@nsc-pdc.UUCP (Joe Mueller) (08/27/85)

> Thus, if you want an array of pointers to arrays of pointers, you can't
> do it.  Nor can you declare functions returning pointers to functions.

You have to be kidding, you can declare both of these things although the
syntax may be a little weird.

Here's an array of 5 pointers to arrays of 6 pointers to char
	char *(*foo[5])[6]	/* how do you like that sports fans! */

Here's a function returning a pointer to a function returning an int
	int (*foo())()

If you have trouble declaring things or deciphering existing code, I highly
recommend a utility called "cdecl". It takes an english description of what
you want and gives you the C syntax for it, it will also take a C declaration
and translate it to an english description of what it is. I used it on the
above examples so I got the declaration right the first time with minimal fuss.
It has been posted to the net at least once before, if you absolutely can't
find it elsewhere and you want a copy, I'll send it to you. If too many people
need it, I'll post it to the net.

The language has hooks to declare incredibly complex data structures, if your
compiler can't hack it, it's not the language's fault.

chris@umcp-cs.UUCP (Chris Torek) (08/27/85)

It is interesting to note that recursive type definitions make
sense only for function pointers, and only because they have side
effects.  Defining (a pointer to)+ makes no sense, because you can
never do anything with it.  It only points.  You can do an infinite
number of indirections and it still just points.

With function pointers, however, indirecting through them causes
side effects; one such effect can be "terminate this program",
which is the magic clause that makes this useful.

Fascinating.

By the way, note that structure declarations such as

	struct foo {
		struct foo *next;
		...
	};

are not really recursive.  The inner entity is a pointer to struct
foo, not a struct foo.

Also by the way, the "most portable" declaration for (function
returning pointer to)+ is probably

	<type> *(*(*foo())())()

as this forces the function to return a pointer to a function that
returns a pointer; even if pointers to basic types are of different
sizes, most any compiler will have pointers to "pointer to function
returning pointer to <type>" being the same size as pointers to
"pointer to function returning pointer to function returning pointer
to <type>" and so forth.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

scott@othervax.UUCP (Scott Pace) (08/27/85)

>> Either I'm missing the perfectly obvious or I've found something
>> that's impossible to declare in C, even though it makes sense.

>You have discovered a fundamental flaw in C type notation.  In essence,
>C allows recursive types only in structs, unions, and enums (and I'm not
>sure how it would be usefull in enums, so that one can be ruled out for
>practical purposes).
>
>Thus, if you want an array of pointers to arrays of pointers, you can't
>do it.  Nor can you declare functions returning pointers to functions.


Well, our compiler seems to handle these sort of constructs ok:-

looking at an array of pointers to arrays of pointers first...

int *(*foo1[10])[];

here foo1 is an array of pointers, each pointer pointing to an array
of pointers to int's.
Thus an integer element might be accessed as follows:

*(*foo1[1])[2] and another way might be **foo1[0]


now looking at functions returning pointers to functions:-

int *(*func1())();

here func is a function returning a pointer to a function, and this
function returns a pointer to an int.
Thus you could do things like:

int *(*func2)(); /*pointer to a function returning a pointer to int*/
int *x;
.
.
.
func2 = func1();
x = (func2)();
.
.
etc.

Cheers

	Scott Pace, ...!philabs!micomvax!othervax!scott

(I hope I got all that right!!!)

throopw@rtp47.UUCP (Wayne Throop) (08/29/85)

I have been inundated with a flood of postings and mail saying "you
can so declare a pointer to a function returning a pointer to a
function".  I started replying by mail, but this proves impractical due
to volume.  Let me introduce my defense as I did in the first letter I
sent out:

"Aaaarrrrgggghhhh!"

There.  I feel better now.  I really *did know* that you can declare
pointers to arrays of pointers to arrays (of primitive types), and
pointers to functions returning pointers to functions (returning
primitive types).  I thought it was clear from the context that I meant
that it is impossible to declare a pointer to a function returning
pointer to function *of that function's own type*.  But noooooooo!  All
you nit-pickers assumed I meant what I said!  Sheeesh!   :-)

In any event, I still maintain that C's type notation is deficent, in
that it only allows recursion in declarations of structs, unions, and
enums (and I haven't found a use for recursion in enums).  It does *not*
allow recursion in type declaractions that contain only pointer,
function, or array constructs.

If you wish to show me the error of my ways, mail or post a typedef F
of a pointer-to-function-returning-type-F.  My claim is that C allows no
such constructs, and that this lack is a shortcoming of the C language.
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!rtp47!throopw