[comp.lang.c] Void function pointers

hpa@casbah.acns.nwu.edu (Peter Anvin) (01/24/91)

Hello everyone.  Could someone please tell me if this is illegal in ANSI C,
or if only Turbo C++ is picky:

void foo(int p1, double p2, void (*zoom)(int x, double y))
{
    printf("Do something with %d and %ld\n",p1,p2);
    zoom(p1,p2);
}

int bar(int baz, double quux)
{
    printf("Zooming... %lf\n",quux);
    return baz;
}

main()
{
   foo(7,3.141592653938789,bar);         /* Turbo C++ gives hard error here */
   return 0;
}

Turbo C++ always terminates with a hard "Type mismatch" error.  Is this
correct behaviour, and if so, is there a way to declare a pointer to a
function returning *anything or void* but still specify its parameters?

Grateful for answer.
    /Peter

P.S. I haven't been able to figure out... is X3J11 ANSI C *finalized* (ANSI
C-90) or are we still muddling around with working drafts?  
-- 
H. Peter Anvin +++ A Strange Stranger +++ N9ITP/SM4TKN +++
INTERNET:  hpa@casbah.acns.nwu.edu   FIDONET:  1:115/989.4
BITNET:    HPA@NUACC                 RBBSNET:  8:970/101.4

sarroyo@govtdev-11w9.shearson.com (Suzanne Arroyo) (01/25/91)

In article <2887@casbah.acns.nwu.edu>  hpa@casbah.acns.nwu.edu (Peter Anvin) writes:
>	Turbo C++ always terminates with a hard "Type mismatch" error.  Is this
>	correct behavior.....?

Yes!  Function foo was defined as:

	void foo ( int p1, double p2, void ( *zoom)(int x, double y))

ie, taking three parameters: an int, a double, and a *pointer to a function returning void**

foo was called later with a pointer to a function returning *int* - causing the obvious
type mismatch

>	is there a way to declare a pointer to a function returning *anything or void* but
>	still specify its parameters?

A function must be declared with a single type - if you want it to be a catch-all type, then
void is your choice - the problem there is passing the right type function pointer

this works, but is messy:
	foo ( 7, 3.131592653938789, (void(*)(int, double) )bar);

hope this helps

--
 Suzanne Arroyo					Wusses Are Fun People!!!!
 Internet: sarroyo@govtdev-11w9.shearson.com
 UUCP:     ...!uunet!slcpi!sarroyo

barmar@think.com (Barry Margolin) (01/25/91)

In article <SARROYO.91Jan24120512@govtdev-11w9.shearson.com> sarroyo@govtdev-11w9.shearson.com (Suzanne Arroyo) writes:
[Regarding passing an int(*)() to a function expecting a void(*)()]
>this works, but is messy:
>	foo ( 7, 3.131592653938789, (void(*)(int, double) )bar);

Is this actually guaranteed to work right?  What if the implementation uses
a different calling sequence for a function returning void from one
returning int?  For instance, the space for a return value might be
allocated by the caller.  Is this allowed (I know they are allowed to use
different calling sequences for varargs functions, but is the return type
also allowed to influence the calling sequence)?  If so, then foo won't
call bar properly.

--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

browns@iccgcc.decnet.ab.com (Stan Brown) (01/25/91)

In article <2887@casbah.acns.nwu.edu>, hpa@casbah.acns.nwu.edu (Peter Anvin) writes:
> 
> void foo(int p1, double p2, void (*zoom)(int x, double y))

So the third argument to 'foo' will be [the name of] a function that does
not return a value.
 
> int bar(int baz, double quux)

Function 'bar' returns an int.

>    foo(7,3.141592653938789,bar);         /* Turbo C++ gives hard error here */

But when you called 'foo' you gave it an int function as third argument.
Returning something is not the same as returning nothing.

> Turbo C++ always terminates with a hard "Type mismatch" error.  Is this

As it should, IMHO.

> correct behaviour, and if so, is there a way to declare a pointer to a
> function returning *anything or void* but still specify its parameters?

I'm 99% sure the answer is No.  A thing is not the same as nothing.

Hey--this is all my opinion, nobody else's. Rely on it at your peril.
                email: browns@ab.com -or- browns@iccgcc.decnet.ab.com
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA    +1 216 371 0043

scjones@thor.UUCP (Larry Jones) (01/26/91)

In article <1991Jan24.181041.4894@Think.COM>, barmar@think.com (Barry Margolin) writes:
> In article <SARROYO.91Jan24120512@govtdev-11w9.shearson.com> sarroyo@govtdev-11w9.shearson.com (Suzanne Arroyo) writes:
> [Regarding passing an int(*)() to a function expecting a void(*)()]
> >this works, but is messy:
> >	foo ( 7, 3.131592653938789, (void(*)(int, double) )bar);
> 
> Is this actually guaranteed to work right?  What if the implementation uses
> a different calling sequence for a function returning void from one
> returning int?  For instance, the space for a return value might be
> allocated by the caller.  Is this allowed (I know they are allowed to use
> different calling sequences for varargs functions, but is the return type
> also allowed to influence the calling sequence)?  If so, then foo won't
> call bar properly.

No, it's not guaranteed to work right.  It will work on many architectures
for many return types, but not all.  Structure return types are the most
likely candidates for misbehavior because the space for a returned structure
is frequently allocated by the caller and the address passed as an additional
argument, so the call does not work.  It is not possible to call a mis-
declared function with predictable results -- casting to the correct type may
shut up the compiler, but it won't make it right.
----
Larry Jones, SDRC, 2000 Eastman Dr., Milford, OH  45150-2789  513-576-2070
Domain: scjones@thor.UUCP  Path: uunet!sdrc!thor!scjones
There's a connection here, I just know it. -- Calvin

gwyn@smoke.brl.mil (Doug Gwyn) (01/26/91)

In article <2887@casbah.acns.nwu.edu> hpa@casbah.acns.nwu.edu (Peter Anvin) writes:
>Turbo C++ always terminates with a hard "Type mismatch" error.  Is this
>correct behaviour, and if so, is there a way to declare a pointer to a
>function returning *anything or void* but still specify its parameters?

Of course the types did not match; that was obvious and the diagnostic
was quite appropriate.

There is no such thing as a C function returning polymorphic types.
If the return value is sometimes needed and is an int then, and is
sometimes not needed, the function should be defined as returning int.

>P.S. I haven't been able to figure out... is X3J11 ANSI C *finalized* (ANSI
>C-90) or are we still muddling around with working drafts?  

Welcome back from Outer Mongolia!

There are now both American and International standards for C;
the two are technically identical for the moment.  ANS X3.159-1989
was approved in December 1989.

gwyn@smoke.brl.mil (Doug Gwyn) (01/26/91)

In article <1991Jan24.181041.4894@Think.COM> barmar@think.com (Barry Margolin) writes:
>In article <SARROYO.91Jan24120512@govtdev-11w9.shearson.com> sarroyo@govtdev-11w9.shearson.com (Suzanne Arroyo) writes:
>>	foo ( 7, 3.131592653938789, (void(*)(int, double) )bar);
>Is this actually guaranteed to work right?

No, for as Lincoln said, calling a tail a leg doesn't make it a leg.

preston@LL.MIT.EDU (Steven Preston) (01/26/91)

In message <2887@casbah.acns.nwu.edu> hpa@casbah.acns.nwu.edu (Peter Anvin) writes:
+ Could someone please tell me if this is illegal in ANSI C:

+ void foo(int p1, double p2, void (*zoom)(int x, double y))
[definition of foo]
+ int bar(int baz, double quux)
[definition of bar]
...
+    foo(7,3.141592653938789,bar);         /* Turbo C++ gives hard error here */

Others have mentioned that this is indeed illegal, and that casting the
address of bar() to the appropriate type will probably work but is not
guaranteed.

I would like to present a correct (I hope) alternative.  If you must call
a function through a pointer without knowing what is being returned, AND
if you are not going to USE any value returned by that function, then
you can just wrap the function inside of a function returning void.

  void bar_foo_callable(int x, double y)
  {
    (void) bar(x,y);
  }

If you DO need to use the result, then use functions that return
pointers to void.  A pointer to any object can safely be cast to a
pointer to void and subsequently cast back to a pointer to the
original type.  Of course, the original type must be known at some
higher level.
--
Steve Preston