From: chupchup@ferkel.ucsb.edu (Robert Earl)
Subject: Re: compiler bug or (I hope) me?
Organization: (EVIL!)
Date: Thu, 3 Sep 1992 08:37:57 GMT

davis@pacific.mps.ohio-state.edu ("John E. Davis") writes:


| #include <stdio.h>
| float fproto(float x)
| {
|    fprintf(stdout, "In fproto, x = %f\n", x);
|    return(2.0 * x);
| }

| float fkr(x)
| float x;
| {
|    fprintf(stdout, "In fkr, x = %f\n", x);
|    return(2.0 * x);
| }

| main()
| {
|    float x,y;
|    long f, *fp;
|    
|    x = 2.0;
|    f = (long) fkr;
|    fp = &f;
|    y = ( (float (*)(float)) (*fp) )(x);
|    fprintf(stdout, "from fkr: %f\n", y);
|    
|    x = 2.0;
|    f = (long) fproto;
|    fp = &f;
|    y = ( (float (*)()) (*fp) )(x);   /* <<---- see text below */
|    fprintf(stdout, "from proto: %f\n", y);
| }

| In fkr, x = 2.000000
| from fkr: 4.000000
| In fproto, x = 0.000000
| from proto: 0.000000

| What am I doing wrong?

Well, I should say that you get what you deserve when you cast a
pointer-to function to a long to a pointer and back again for the
function call.  But the real reason is that functions with old-style
definitions go by the old-style promotion rules.  In other words,

float f(x) float x; { return x; }

is NOT equivalent to

float f(float);

but it IS equivalent to 

float f(double);

The reverse is also true; when calling a new-style function with an
old-style prototype in scope, the arguments in the actual function
just cannot be "float", because there is no way to pass an unpromoted
float value this way.  By the way, you are lucky your keyboard didn't
turn into a goat; this is undefined behavior as described in K&R 2,
A7.3.2:

	"The effect of the call is undefined if ... the type of an
argument after promotion disagrees with that of the corresponding
parameter.  Type agreement depends on whether the function's
definition is new-style or old-style.  If it is old-style, then the
comparison is between the promoted type of the argument of the call,
and the promoted type of the parameter; if the definition is
new-style, the promoted type of the argument must be that of the
parameter itself, without promotion."

| Compare with the BCC++ manual:
| (page 55, programmers guide):

|       ``...Under C++, which has stronger type checking, a pointer to a
|       function has type ``pointer to function taking argument types
|       `type' and returning `type'.'' In fact under C a function
|       defined with argument types will also have this narrower type.
|       For example:

|          void (*funct)();

|       In C, this is a pointer to a function returning nothing.  In
|       C++, it is a pointer to a function taking no arguments and
|       returning nothing....''

More accurately, this is a pointer to a function prototyped "as if" by
"void funct();", namely, an old-style prototype.  My statement would
be equally true for C++ as well; Borland's is a bit shaky, after all,
if you want a pointer to a function taking no arguments and returning
nothing, just use "void (*funct)(void);".  It's not that much more
typing.  :-)


-- 
"If you've got a pig that likes jumping fences, | robert earl
you have to make its fence a lot higher all at  | rearl@ucsd.edu
once -- if you do it by increments, all you're  | rearl@piggy.ucsb.edu
doing is training a jumping pig." -Henry Spencer|
Newsgroups: comp.lang.c,comp.misc