Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Casting void - int question

8 views
Skip to first unread message

Michael T. Heins

unread,
Oct 13, 1986, 12:00:39 PM10/13/86
to
[]
Could someone suggest the proper way to handle the following problem?

I have a number of existing functions with compatible arguments. Some
are declared as void, and others as int. None of the return values are
used. I wish to set up an array of pointers to these functions.

My problem is that the compiler complains about incompatible types, and
I can't figure out how to use casts or unions to solve the problem.

Re-declaring the functions is not an option. I have exemplified the
situation below:

int fna() { }

void fnb() { }

int (*array[32])();
main() {
array[0] = fna;
array[1] = fnb; /* This won't work as-is. */
}

I have tried things like
array[1] = (int (*)())fnb;
but this generates the message "operands of CAST have incompatible types".

Any help would be appreciated.

--
...!hplabs!sdcrdcf!trwrb!orion!heins

We are a way for the universe to know itself. -- Carl Sagan

Tom Stockfisch

unread,
Oct 14, 1986, 10:44:20 PM10/14/86
to
In article <2...@orion.UUCP> he...@orion.UUCP (Michael T. Heins) writes:
>
>int fna() { }
>
>void fnb() { }
>
>int (*array[32])();
>main() {
> array[0] = fna;
> array[1] = fnb; /* This won't work as-is. */
>}
>
>I have tried things like
> array[1] = (int (*)())fnb;
>but this generates the message "operands of CAST have incompatible types".

The compiler rightly complains because
void (*)()
could conceivably be larger than
int (*)()
on some wierd machine. You should use a union, e.g.:

union int_or_void_func {
int (*int_func)();
void (*void_func)();
} array[32];

main()
{
array[0].int_func = fna;
array[1].void_func = fnb;
}

The above is the much preferred way to do this. However,
if you want to initialize "array[]", you currently can't use a union (ANSI
standard may change this). Then the portable way to do this is

int fna();
void fnb();

char *array[32] = {
(char *)fna,
(char *)fnb
};

main()
{
( *(int (*)())array[0] )(); /* call fna */
( *(int (*)())array[1] )(); /* call fnb */
}

If this won't work on some machines, I would appreciate hearing an explanation
from some guru.
A disadvantage of this method, besides ugliness, is that lint gives the
complaint
questionable conversion of function pointer
for each element of array that you initialize, and each call as well. In
any application where I use this method I wind up creating a lint filter
such as
grep -v 'questionable conversion of function pointer'
and use it on all lint output.
--

-- Tom Stockfisch, UCSD Chemistry

bri...@dataio.uucp

unread,
Oct 15, 1986, 12:54:28 PM10/15/86
to
In article <2...@orion.UUCP> he...@orion.UUCP (Michael T. Heins) writes:
>I have a number of existing functions with compatible arguments. Some
>are declared as void, and others as int. None of the return values are
>used. I wish to set up an array of pointers to these functions.
>My problem is that the compiler complains about incompatible types, and
>I can't figure out how to use casts or unions to solve the problem.
>Re-declaring the functions is not an option. I have exemplified the
>situation below:
>
>int fna() { }
>void fnb() { }
>
>int (*array[32])();
>main() {
> array[0] = fna;
> array[1] = fnb; /* This won't work as-is. */
>}
>
>I have tried things like
> array[1] = (int (*)())fnb;
>but this generates the message "operands of CAST have incompatible types".

int fna() { }
void fnb() { }

int callfnb() { fnb(); }

int (*array[32])();
main() {
array[0] = fna;

array[1] = callfnb;
}

Messy, but workable.

thr...@dg_rtp.uucp

unread,
Oct 18, 1986, 1:57:37 PM10/18/86
to
> he...@orion.UUCP (Michael T. Heins)

> My problem is that the compiler complains about incompatible types, and
> I can't figure out how to use casts or unions to solve the problem.

Well, the cast solution you gave ought to have worked. And, indeed, it
works for the compiler and lint that I use. The draft ANSI C document
has this to say, in 3.3.4:

A pointer to a function of one type may be converted to a pointer to
a function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to
call a function of other than the original type, the behavior is
undefined.

So, the good news is that draft ANSI says the cast must work. On the
other hand, the bad news is that you can't portably use the cast pointer
to invoke the function. Sigh.

On the third hand, almost all extant C compilers (which support the
relevant types) will work correctly when a pointer expression of type
(int (*)()) is used to invoke a function of type (void ()). On the
fourth hand (look, ma! four hands!), if you *really* want to be
portable, you might should do something like this:

/* to declare the array of functions to call */
typedef union { void (*v)(); int (*i)();} func_ptr_t;
typedef enum {void_func, int_func} func_kind_t;
typedef struct { func_kind_t kind; func_ptr_t ptr; } func_desc_t;
func_desc_t func_desc[N];

/* to install a new function */
switch(func_kind){
case(void_func): func_desc[i].ptr.v = some_void_func; break;
case(int_func): func_desc[i].ptr.i = some_int_func; break;
}
func_desc[i].kind = func_kind;

/* to invoke a function */
switch(func_desc[i].kind){
case(void_func): (*func_desc[i].ptr.v)(); break;
case(int_func): (*func_desc[i].ptr.i)(); break;
}

OK, OK, so it's ugly *ugly* *UGLY*!!! On the other hand, it is the
simplest portable method I've come up with that does the job and
directly invokes the function. It is also possible to do it a more
flexible way which trades an extra function invocation for the switch at
invocation time (and which can be expanded to invoke more types of
functions without changing the invocation code). This method isn't
really any simpler in its general form, and is left as an excersize for
the masochistic reader.

--
Like punning, programming is a play on words.
--- Alan J. Perlis
--
(By the way, "might should" (along with "might could" and other
might-modified forms) is a feature of the local dialect that I threw in
there on purpose for whimsical effect. I did realize it isn't quite
correct when I did it. Really. No, wait, I really *did* do it on
purpose! Where's everybody going? Don't you believe me? You can't
just walk out on me like this!! COME BACK! WAIT... oh, what's the
use? At least I linted my examples... hmpf!)
--
Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

Wayne Throop

unread,
Nov 3, 1986, 5:26:13 PM11/3/86
to
> ch...@umcp-cs.UUCP (Chris Torek)

> The cast is correct, but the 4.1 and 4.2BSD compilers misunderstand
> void functions. --
Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

Wayne Throop

unread,
Nov 3, 1986, 5:38:33 PM11/3/86
to
> ch...@umcp-cs.UUCP (Chris Torek)

> The cast is correct, but the 4.1 and 4.2BSD compilers misunderstand

> void functions. `void' types in these compilers tend to cause all
> sorts of internal indigestion. This is a bug.

Exactly right, of course.

> Lint should note the cast as non-portable.

99 and 44/100 percent right. The *cast* is portable. But invocation
of a function via a cast pointer to a function of differing type is not.
Of course, lint may not be able to catch such subtleties easily, and the
cast itself might be an appropriate place to warn.

--
"Greater nits have little nits, upon their backs to bite 'em.
And little nits have lesser nits, and so ad-infinitum..."
--- (can't recall who I'm paraphrasing... Ogden Nash probably...)

0 new messages