[net.unix] functions returning pionters to func

mbr@fortune.UUCP (12/15/83)

#R:azure:-243000:fortune:26900002:000:1701
fortune!mbr    Dec 14 12:34:00 1983

The easiest solution would be to use typedef:

	typedef int (*Fint)();

	Fint getroutine(name, table)
	type declaration for name & table;
	{
		.
		.
		.
	}

Your original solution of:

	int (*getroutine())(name, table)

was close.  If you don't want to use typedef, the correct declaration is:

	int (*getroutine(name, table))()

I've tried this on 4.1, and cc is quite happy with it.

Declarations of this complexity frequently get me muddled as well.  I find
the easiest way to think of it is to write the expression in which the
type would appear, successively adding layers until I've reached a simple
type (such as int), and then turn that into the declaration.  For example:

	1. Getroutine is a function, so the expression to  call it would look
	   like:

		getroutine(name, table)

	2. The return value from getroutine is a pointer, so the expression to
	   access its contents is:

		*getroutine(name, table)

	3. The value it points at is the entry point of a function, so the
	   expression to call the function is:

		(*getroutine(name, table))()

	4. The value this function returns is an integer.  The call to this
	   function would use the returned integer for something integerlike:

		i = (*getroutine(name, table))();

	   or:

		if ( (*getroutine(name, table))() == 999)
		{
			/* do something */
		}

	   however, in a type declaration, you just need to state that what
	   you've come up with is an integer and then define your function:

		int (*getroutine(name, table))()
		type declaration for name & table;
		{
			.
			.
			.
		}

			Mark Rosenthal
			{allegra,amd70,cbosgd,dsd,floyd,harpo,hpda,ihnp4,
			 magic,megatest,nsc,oliveb,sri-unix,twg,varian,wdl1}
			!fortune!mbr

rpw3@fortune.UUCP (12/17/83)

#R:azure:-243000:fortune:26900005:000:2673
fortune!rpw3    Dec 17 00:16:00 1983

Lo, I too have fought the mighty type-check and been victorious!
(Enough ancient grammer...)

The following code was the result of trying to declare a VARIABLE (as
opposed to the original submitter's ROUTINE) named "state", said
variable to hold the address of an array of routines, each of which
returns a value of the same type as "state" (i.e., a pointer to an
array of routines which...).

In case you haven't guessed, this is to build FAST state machines for
which the state and an input value maps directly to an action routine.
The application was, well, never mind... Each interrupt would process
all of the state transitions needed until no more work could be done.

After I had stumbled through all of the hassles mentioned previously,
I finally solved it using typedefs, but wasn't happy, since there seemed
something inelegant about that. The following program does it WITHOUT
typedefs (although the typedef version is easier to read, and was what
was used in production). Read carefully! The line that starts "struct..."
is actually declaring "state". (Ignore the missing initialization of "state")

Rob Warnock

UUCP:	{sri-unix,amd70,hpda,harpo,ihnp4,allegra}!fortune!rpw3
DDD:	(415)595-8444
USPS:	Fortune Systems Corp, 101 Twin Dolphins Drive, Redwood City, CA 94065

----------- sm.c --------------
extern char DR_flags;	/* argument to each state handler */

struct foo	{ struct foo (*(*dummy)())[];	} (*state)[];

/* called on each interrupt */
smachine()
{
	state = FIRSTSTATE;	/* defining FIRSTSTATE is hard, too */
	while (state)
	    state = (*((*state)[DR_flags].dummy))();  /* turn the crank */
}
---------------------------------

Here is the compiled code for a couple of machines. The typedef version
gives the same code, but the dummy struct member is avoided.

----------- smpdp10.mac ------------- (compiled from the original BLISS)
state::	block 1

_smachine::
	skipne	1,state
	popj 17,
	add	1,DR_flags##
	pushj	17,@(1)
	movem	1,state
	jrst	_smachine
----------- smvax.s -------------
.data
.comm	_state,4
.text
LL0:.align	1
.globl	_smachine
.set	L14,0x0
.data
.text
_smachine:.word	L14
jbr	L18
L2000001:cvtbl	_DR_flags,r0
ashl	$2,r0,r0
addl2	_state,r0
movl	(r0),r0
calls	$0,(r0)
movl	r0,_state
L18:tstl	_state
jneq	L2000001
ret
----------- sm68.s --------------
	.data
	.comm	state,4
	.text
	.globl	smachine
smachine:
	|.proc
	link	%a6,#-.F1
	movl	%a2,%sp@
	movl	#state,%a2
	jra	.L15
.L20001:
	movb	DR_flags,%d0
	extw	%d0
	extl	%d0
	asll	#2,%d0
	addl	%a2@,%d0
	movl	%d0,%a0
	movl	%a0@,%a0
	jsr	%a0@
	movl	%d0,%a2@
.L15:
	tstl	%a2@
	jne	.L20001
	movl	%a6@(-.F1),%a2
	unlk	%a6
	rts
.F1 = 4
	.S1 = 1024
	.data

----------end--------------------

shah@fortune.UUCP (12/17/83)

#R:azure:-243000:fortune:26900008:000:1551
fortune!shah    Dec 17 02:47:00 1983

+------
|    fortune:net.unix / rpw3 / 12:16 am  Dec 17, 1983
|                      ....
| I finally solved it using typedefs, but wasn't happy, since there seemed
| something inelegant about that. The following program does it WITHOUT
| typedefs (although the typedef version is easier to read, and was what
| was used in production).
|                      ....
|  struct foo      { struct foo (*(*dummy)())[];   } (*state)[];
|                      ....
+-------

    Something that makes reading (comprehension) easy seems
more elegant to me.  Coming up with the right struct
definition without using typedefs IS more challenging (even
reading it is challenging, every time!) but elegant it is not.

    Like routines typedefs are a factoring mechanism.  Unlike
routines they cost you nothing at runtime.  I recommend
everyone to use them where appropriate; they are free.

    The key concept in Rob's problem is how to define a
recursive type involving a routine ptr.  Here is a simpler
problem with that property:

        Let f be a pointer to a routine.  Define f so that the
    result of the routine pointed to by f can be assigned to
    f.  The assignment must be typesafe and must not use any
    casts.

    Try to solve this with typedefs and then without.  The
compiled code of a correct solution will be identical to code
of

    typedef char * (*fType)();
    fType f;

    f = (fType) (*f());

    Please do not post any solution(s) to net -- not too soon,
anyway.  Anyone else have REALLY tough C puzzles?

				    -- Bakul Shah

shah@fortune.UUCP (12/18/83)

#R:azure:-243000:fortune:26900009:000:149
fortune!shah    Dec 17 14:18:00 1983

:-(
    There was an error in the test for a correct solution.
Replace "f = (fType) (*f())" with "f = (fType) (*f)()".
Sorry about that.
			-- Bakul