function pointer help needed

15 views
Skip to first unread message

Jim Vaxkiller

unread,
Jan 9, 1987, 4:36:10 PM1/9/87
to
I'm having a little problem with tables of pointers to functions.
What I want to do is have several functions returning type void,
then put their addresses into a table and execute the function by
indexing into the table. Assembly language programmers out there
will recognize this as a simple jump table. Now if I have my functions
return ints I'm fat, dumb, and happy. It's when I try to use functions
returning voids that the compiler burps. I know about the void problem
in the 4.2BSD compiler and have typedef'd voids to ints, but to no avail.
The following code fragment illustrates my problem.


void /* 2 do nothing routines returning */
err0() /* different data types */
{}

int
err1()
{}

static (*ptr_tbl[])() = { /* table of 2 function pointers */
err0, /* this is what the compiler hates */
err1
};

main()
{
(*ptr_tbl[0])(); /* invoke function */
}


Granted, I could have my functions all return ints, but I don't want
to do that because they don't return anything and lint complains.
My system is a vax 11/750 running 4.2BSD UN*X. Any suggestions on
how to make this work would be much appreciated.


Jim

Jim Harkins
Loral Instrumentation, San Diego
{ucbvax, ittvax!dcdwest, akgua, decvax, ihnp4}!sdcsvax!sdcc6!loral!jlh

Alan Amaral

unread,
Jan 12, 1987, 1:03:32 PM1/12/87
to


Here is one way:

void /* 2 do nothing routines returning */
err0() /* different data types */

{printf("testing 123\n");}

int
err1()
{}

void (*ptr_tbl[2])(); /* table of 2 function pointers */

void init()
{
ptr_tbl[0] = err0;
}

main()
{
init();


(*ptr_tbl[0])(); /* invoke function */
}


Here is another way:

int /* 2 do nothing routines returning */


err0() /* different data types */
{}

int
err1()
{}

static (*ptr_tbl[])() = { /* table of 2 function pointers */
err0, /* this is what the compiler hates */
err1
};

main()
{
(void) (*ptr_tbl[0])(); /* invoke function */
}


Neither causes complaints from cc or lint (except for the unused err1 in
the first example that is). I have found that this method is VERY nice
for doing lots of different things cleanly. For example, I have a Ray
Tracing program that uses this sort of mechanism all over the place for
keeping methods straight for each object that I am rendering. For
example:

/* intersect ray with all known objects */
for(i=0; i<n_objects; i++)
(* object_list[i].intersect) (i,ray);

causes the intersection algorithm for each object to be called, causing
each object to intersect itself with the supplied ray. This wouldn't be
necessary normally except that each object type has a different
mechanism and routine for the intersection process. It could also be
done by calling an intersection routine that had a case statement and
checked what type of object each object was and called the right
algorithm, but this is so much cleaner. Also, to add a new object is
almost trivial after the object specific code is written. The mechanism
is as follows: In the initialization routine an array entry is filled
with the address of a routine that reads the data for each specific object
type. When an object type is encountered the jump table causes the
corresponding routine to be called. In the object read routine the data
is read and the address's for all the other methods (intersection,
shadowing, and attributes i.e. color or texture) are filled into the
object structure. When the object is to be intersected, shadowed, or
the attributes of the object at a particular point are requested, the
requesting routine indexes into the object_list array (as above) and
calles the correct routine with the correct parameters.

This has a very clear advantage over every other method I have ever
used in that to add a new object type, all I have to do is to add a new
line in the initialization routine to load the object read routine, and
the object read routine fills in the rest. It's especially nice in that
I can supply only the code that needs to be changed (the init routine)
in source format, and the rest in object format, and the user can add
new objects just like a UNIX s/p can add a new device driver.
--
uucp: ...decvax!elrond!amamaral I would rather be a
phone: (603) 885-8075 fool than a king...
us mail: Calcomp/Sanders DPD (PTP2-2D01)
Hudson NH 03051-0908

Wayne Throop

unread,
Jan 12, 1987, 3:29:51 PM1/12/87
to
> j...@loral.UUCP (Jim Vaxkiller)

> I'm having a little problem with tables of pointers to functions.
> What I want to do is have several functions returning type void,
> The following code fragment illustrates my problem.
> void err0() {}
> int err1() {}
> static (*ptr_tbl[])() = { err0, err1 };
> main() { (*ptr_tbl[0])(); }

You have declared ptr_tbl to be an array of pointers to functions
returning int, and err0 is a pointer to a void function. You must use
casts or unions if you wish to have an array of pointers to functions of
more than one type. Unions are probably the best method, though there
are problems with initializers for unions. I don't see any portable way
to statically initialize an array of pointers to functions of differing
types.

--
You see, wire telegraph is a kind of very, very long cat.
You pull his tail in New York and his head is meowing in Los
Angeles. Do you understand this? And radio operates exactly
the same way: you send signals here, they receive them there.
The only difference is that there is no cat.
--- Albert Einstein
--
Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

Ron Natalie <ron>

unread,
Jan 14, 1987, 5:52:07 PM1/14/87
to
In article <13...@loral.UUCP>, j...@loral.UUCP (Jim Vaxkiller) writes:
> I'm having a little problem with tables of pointers to functions.
> What I want to do is have several functions returning type void,
> then put their addresses into a table and execute the function by
> indexing into the table.
> The following code fragment illustrates my problem.
>
> void /* 2 do nothing routines returning */
> err0() /* different data types */
> {}
> int
> err1()
> {}
> static (*ptr_tbl[])() = { /* table of 2 function pointers */
> err0, /* this is what the compiler hates */
> err1
> };

Hold the phone! Lets look at what you've done.

First..ptr_tbl is declared as an array of pointers to functions
returning INT. If you don't specify a type it is INT. You could
fix problem #1 by making it read "static void (*ptr_tbl[])()"

Second. You do not have a set of functions returning VOID or INT.
You have a combination. You seem to expect clairvoyance by the
compiler. It is required that when the compiler calls a function
that it knows what type the function is going to return. This is
required because calls to functions returning different types may
require different linkages even if you are not going to look at the
return value. For example, functions returning struct usually want
to write the return value into some allocated area on the stack which
you must set up even if you are casting the return to void.

If you generate a table of mixed types then how is the compiler going
to know which linkage to use for which function. C has to "typeof"
operator that can be applied to contents of a pointer to find out what
the pointer was pointing to (although some architectures actually support
this).

Make all your functions return the same type. In this case, void.
If you have a function returning something else, then encapsulate
it in a void function, e.g...

struct foo goo();

void vgoo() {
(void) goo();
}

and include vgoo in your table.

-Ron

Ron Natalie <ron>

unread,
Jan 14, 1987, 5:57:36 PM1/14/87
to
In article <5...@elrond.UUCP>, amam...@elrond.UUCP (Alan Amaral) writes:
> In article <13...@loral.UUCP>, j...@loral.UUCP (Jim Vaxkiller) writes:
> Here is one way:
>
> void /* 2 do nothing routines returning */
> err0() /* different data types */
> {printf("testing 123\n");}
>
> int
> err1()
> {}
>
> void (*ptr_tbl[2])(); /* table of 2 function pointers */
>
> void init()
> {
> ptr_tbl[0] = err0;
> }

WARNING WARNING...DANGER DANGER...RUN, WILL ROBINSON, RUN!

Gak...don't do this. While most compilers will treat this OK since the
place where an "int" is returned is generally considered scratch before
a funcion is called, this is NOT PORTABLE, and will break most compilers
if err0 returned something large like a structure.

The linkage of a subroutine is dependant on the value it returns. Casting
it into a pointer to a function returning a different type is asking for
trouble.

-Ron

lat...@bsdpkh.uucp

unread,
Jan 16, 1987, 2:58:48 AM1/16/87
to
in article <13...@loral.UUCP>, j...@loral.UUCP (Jim Vaxkiller) says:
> Keywords: (*ptr[i])() = ???

>
> I'm having a little problem with tables of pointers to functions.
> What I want to do is have several functions returning type void,

Try using the following .....

void err1() {} /* NOTE : these are functions returning void !
void err2() {}
extern void err3();

static void (*ptr_tbl[])() = {
err1, /* this is a table of pointers to functions */
err2, /* that return void ....... */
err3 /* previously you defined them as returning int */
/* because you only stated that they we static */
/* thus they returned int BY DEFAULT */


};

main()
{
(*ptr_tbl[0])(); /* invoke function */
}

A POINTER TO A FUNCTION HAS A TYPE ... it is the type that the function
returns. If you wish to set up a table of said pointers, then you must
declare its elements as pointers to functions returning that type.

I HAVE TRIED THE ABOVE .... to avoid foot in mouth disease. The only
reason it didn't compile was that err3 was an undefined symbol. (sysVr2.1)
************************************************************************

"There is not now, nor will there ever be, a computer language
in which it is the least bit difficult to write bad programs."
-Unknown

Ken Latham
uucp: ..!ihnp4!bsdpkh!latham

P.S. The quote in the signature is not directed at the writer of the
original article .... it is just somthing I believe.

Reply all
Reply to author
Forward
0 new messages