[net.lang.c] Ptr to func doesn't like casting??

greenber@acf4.UUCP (11/26/84)

<>

Here is an interesting one (I think!!):

given a declaration such as:

int	(* varname)();

it certainly should point to a function returning int.
Now if I wish to temporarily hold a pointer to a string there, and I
get the pointer from a function:

char	*function();

	varname = function();

barfs in any of the lint-like guys I use with a legitimate gripe, that
is "pointers don't point to same object, you dumbo!".

Well,

	(char *)varname = function();
doesn't work (lvalue required).

And,
	varname = (*function())();
doesn't work consistantly.

So what's a poor boy to do?  In particular, I am using this under Lattice C.
Let me know at the below address:


Ross M. Greenberg  @ NYU   ---->  allegra!cmcl2!acf4!greenber  <----

henry@utzoo.UUCP (Henry Spencer) (11/27/84)

> [Trying to store a char pointer in a function pointer is hard to get
> past the compiler/lint]
> 
> 	(char *)varname = function();
> doesn't work (lvalue required).
> 
> And,
> 	varname = (*function())();
> doesn't work consistantly.

Well, you might try:

	varname = (int(*)())function();

which is the correct cast form -- get the value from the function and
then cast it to pointer-to-int-function.

However, I am morally bound to tell you that you are sinning :-), and in
a somewhat unportable way.  Pointers to functions and pointers to data
are very different animals, and on some machines they are of different
sizes.  Using one to hold the other is hazardous.  I believe the ANSI C
draft outlaws such conversions altogether, although I haven't got my
copy handy to check.  Use a union; it's much more portable, and should
shut the compilers up as a useful bonus.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (11/30/84)

A friend has pointed out that although the ANSI C draft does indeed
outlaw casts between function pointers and data pointers, it lists
such casts in the "common extensions" appendix.  It's hard to do things
like debuggers and on-the-fly code generation without such casts.  But
use of casts, instead of unions, for more mundane requirements remains
a poor idea.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

greenber@acf4.UUCP (11/30/84)

<>


Okay....I've received about three million, two hunderd and six responses
regarding this casting question.  Thank you one and all.

Everybody told me basically the same thing:

	(int (*)())  is the way to cast.

Then they cast(igated) me for using a non-portable cast.  Some indicated
that the primary problem of this cast was that the ptr to function is
supposed to point to instruction space and might barf if it points to
data space on a machine that cares (I&D --- where have I heard that before?).

A few indicated that I should really use unions.  That's a nogo, since
I use the structure that this is a part of as an initializer.

But I've tried this casting on every machine that I can get my hands on
and it seems to work  (either that or that cast turns on the "shut-up"
flag automagically in lint! :-) ) .  I would be interested in finding out
what machines it WILL NOT work on.

Thanks again, guys!!


Ross M. Greenberg  @ NYU   ---->  allegra!cmcl2!acf4!greenber  <----

greenber@acf4.UUCP (12/01/84)

<>


This is by far the most definitive example that I received....so good
that I just couldn't help posting it  (John, I hope you forgive me!!)
Thank you John....and I bet this helps out others....
========================================================================

Ross -- I can understand your confusion, I got confused about the
same thing when I was "only an egg".  We have:

int (*varname)();	/* You're right, this is a
			 *	Pointer		 to a
			 *	Function	 returning an
			 *	int
			 */

char *function();	/* a function returning char *, clearly */

Now,
	varname = function();
will work on some, perhaps most, CPUs but will not lint; as you
say, why should it?  It is wrong.

And
	(char *)varname = function();
isn't C, as you found out; I can't understand why people want
to try writing that, it never occured to me.

Your other try:
	varname = (*function())();
is a real doozy!  Like, it's semantically very different (and sure as hell
won't lint, let alone working).  It says:
	Invoke function(), get a char *
	Apply * to that, getting a char
	Coerce the char into a (deep breath):
		pointer to a
		function returning a
		pointer to a
		function returning an
		int
	[this is "implied but not stated"]
	Invoke the pointed-to function (!) [the second set of () means this]
	Store the result in varname.
So you can see there are TWO function calls there, and the second one had
its address made out of a char, which is hardly likely to do anything good.
This is most unlikely to compile on any modern compiler, and I do not think
even a V6-style "lax" compiler would let it go by unchallenged.

So, you ask, what do I do?  Well, it's simple when you know how:

	varname = (int (*)())function();

That's the cast you want.  A useful rule to help you construct casts to complex
types is:
	Think of a declaration for a variable of that type
			[ int (*fp)(); ]
	Take the identifier out, lose the semicolon
			[ int (*)() ]
	Enclose the whole thing in parentheses
			[ (int (*)()) ]
	Voila!

Just by the way, our "lint" (we're running a heavily hacked V7) says that
this is a "questionable conversion of function pointer".  And it
probably is, too.  (SysVr2 lint says the same.)  But at least that's
the correct cast!

John Mackin, Physiology Department, University of Sydney, Sydney, Australia
...!decvax!mulga!physiol.su.oz!john

kpmartin@watmath.UUCP (Kevin Martin) (12/02/84)

>I am morally bound to tell you that you are sinning :-), and in
>a somewhat unportable way.  Pointers to functions and pointers to data
>are very different animals, and on some machines they are of different
>sizes.  Using one to hold the other is hazardous.  I believe the ANSI C
>draft outlaws such conversions altogether, although I haven't got my
>copy handy to check.  Use a union; it's much more portable, and should
>shut the compilers up as a useful bonus.
>				Henry Spencer @ U of Toronto Zoology

I always had the impression K&R didn't make an exception for function
pointers when it stated that different pointer types can be cast into
each other. Oh well.

I am certainly aware of machines where using a function pointer cast to
call a function as if it returned a different type would lead to disaster.
But on these machines, you could cast the pointer all you wanted to,
as long as it came back to the original type before being used for a
function call.

What does the ANSI committee suggest for a generic function pointer? Or
does (void *) still work?

Using a union is not always a practical solution. For instance, in
a library routine which takes as an argument a function pointer, for
later use by the caller (not the callee). You would have to have a union
of all possible types of functions. Even if the library routine restricts
the types that the function can return, you still need to be able to
"cast" the supplied function pointer into the union.
e.g. I can't say
	libfunc( (void *)myfunc );
instead, I must say
	union functypes junk_variable;
	junk_variable.ret_type_1 = myfunc;
	libfunc( junk_variable );

(Another example might be some sort of dynamic-linking function or
overlay loader which returns a pointer to the loaded function. Surely
such a beast cannot return a union of *all* types of functions!)

Are there machines which cannot cast a function pointer into another
pointer (e.g. (void *)) and back? After all, you can cast any pointer
into an implementation-dependant integral type and back without loss
of information...
                      Kevin Martin, UofW Software Development Group.

bsa@ncoast.UUCP (Brandon Allbery) (12/03/84)

> Article <13900010@acf4.UUCP>, from greenber@acf4.UUCP
+----------------
| given a declaration such as:
| 	int	(* varname)();
| it certainly should point to a function returning int.
| Now if I wish to temporarily hold a pointer to a string there, and I
| get the pointer from a function:
| 	char	*function();
| 	varname = function();
| barfs in any of the lint-like guys I use with a legitimate gripe, that
| is "pointers don't point to same object, you dumbo!".
| 
| Well,
| 	(char *)varname = function();
| doesn't work (lvalue required).
| And,
| 	varname = (*function())();
| doesn't work consistantly.
| 

Perhaps lint and our C are more closely related than I thought they might
be; I once tried to use a

	typedef int (*func)();

and cc barfed all over it.  I forget what error it gave, except that
it looked like it was ignoring the pointer nature of the thing.  Anyone
know whence came this piece of brain-damage?

--bsa
-- 
  Brandon Allbery @ North Coast Xenix  |   the.world!ucbvax!decvax!cwruecmp!
6504 Chestnut Road, Independence, Ohio |       {atvax!}ncoast!{tdi1!}bsa
   (216) 524-1416             \ 44131  | E1439@CSUOHIO.BITNET (friend's acct.)
				       |    BALLBERY (161-7070) on MCI Mail
---------------------------------------+---------------------------------------
	      Keeping the Galaxies safe for Civilization... :-)

bsa@ncoast.UUCP (Brandon Allbery) (12/03/84)

One other thing about that final cast:  if I read it correctly, the compiled
code will attempt to execute the string!  You are treating the output
of the function() as a pointer to a function and CALLING it.  The correct
cast is:

	var = ((*int)()) function();

if I remember correctly.

--bsa
-- 
  Brandon Allbery @ North Coast Xenix  |   the.world!ucbvax!decvax!cwruecmp!
6504 Chestnut Road, Independence, Ohio |       {atvax!}ncoast!{tdi1!}bsa
   (216) 524-1416             \ 44131  | E1439@CSUOHIO.BITNET (friend's acct.)
				       |    BALLBERY (161-7070) on MCI Mail
---------------------------------------+---------------------------------------
	      Keeping the Galaxies safe for Civilization... :-)

henry@utzoo.UUCP (Henry Spencer) (12/11/84)

> I always had the impression K&R didn't make an exception for function
> pointers when it stated that different pointer types can be cast into
> each other. Oh well.

K&R didn't, but then we all know that casts were a pretty late addition
to C and K&R didn't really describe them very well at all.

> What does the ANSI committee suggest for a generic function pointer? Or
> does (void *) still work?

They don't have any specific suggestion that I've seen.  "void *" is the
generic pointer-to-object, but functions are not objects.

> Using a union is not always a practical solution. ...

Agreed.  Note that you *can* cast pointers to functions around "among
themselves", so to speak; it's just that you can't mix them with pointers
to objects without trouble.  So you need to start thinking about unions
only in really unusual situations.  The example you give (passing a
generic "pointer to function") isn't a problem here, although it would
be nice if there were a function-pointer equivalent of "void *".

> Are there machines which cannot cast a function pointer into another
> pointer (e.g. (void *)) and back? After all, you can cast any pointer
> into an implementation-dependant integral type and back without loss
> of information...

I'm not aware of any... but they may exist.  Casting pointers to the
proper integral type and back is always workable; perhaps this is the
thing to do in dire extremity.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry