Link to home
Start Free TrialLog in
Avatar of Stephen Kairys
Stephen KairysFlag for United States of America

asked on

implict prototype determined when passing function to another function?

Hello all.
This question is somewhat related to

https://www.experts-exchange.com/questions/21377175/looks-like-a-prototype-but-really-isn't.html

where we discussed such wonderful "features" of C like
inconsistent prototyping.

Now, I encountered another good one (amazing what
you find when combing through old code)

-----------ZIPCODE.C-----------

// K & R format. You'd never know it, but this
// function actually takes two parameters.
void display_zipcode_data();

.....
now later on, this function is passed to another function
that expects a function pointer...

foo(display_zipcode_data)

Now, foo expects that the function passed into it
takes a long, a short, and a char*.  So, will C
then use that info to "create" an implicit prototype,
much like it might if I called the function
explicitly...i.e

display_zipcode_data(mylong, myshort, mycharpointer);
???

Thanks
Steve

PS-Sorry for the odd# of points, it's all I have left :)


ASKER CERTIFIED SOLUTION
Avatar of efn
efn

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of NovaDenizen
NovaDenizen

C lets you pretty much cast anything into anything else as long as you do it explicitly.  You can take a pointer to a function that has only been mentioned in a K&R argumentless prototype, then cast it to any other kind of function you want.  Of course, the best way to do it is:

...in headers
typedef void foofunc(long, short, char *);
foofunc display_zipcode_data;
void foo(foofunc);

... in some source file
void display_zipcode_data(long l, short s, char * cp) {
...
}

... in a function in some other source file:
    foo(display_zipcode_data);

... in some other source file:
void foo(foofunc func) {
 .....
     func(l, s, cp);
....
}



void foo(foofunc func) {
}

Avatar of Stephen Kairys

ASKER

>>If you pass the function a long, a short, and a char, the compiler obediently generates code to do that, but it doesn't generate a prototype in the sense that it will later complain if you pass the same function a different set of parameter types.<<

So, if I pass the function an int, and the actual function def'n expects a char, what takes
precedence?

e.g.
void foo()

....in calling routine...
int i;
foo(i);

...and further down....
void foo(char c)
....

thanks
I'm not sure what you mean by "takes precedence."

The generated code passes an int to the function and the function treats it as a char.  In this particular case, probably nothing would break, because a char parameter automatically gets promoted to int, so the calling and called functions would agree on the size of the parameter.
By "takes precedence" I guess I meant "who wins the argument".
The caller code says "IT SHOULD BE AN INT"
The function code says "NO, IT SHOULD BE A CHAR"

so I guess I meant...what will it be...INT or CHAR?
thanks
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Efn,
Well put!
Now, just to be sure I understand:

to further your example:

void readmail(ScrambledEgg se); // here I have a real prototype

readmail(se);

void readmail(Letter missive)
{
  read missive;
}

I guess the same thing would apply here, right?

>>Or, one might say, that's what you get for using C, which lets you get away with such shenanigans.<<

Yean, my thoughts exactly.  Makes me yearn for the days
of programming in Pascal, both in all-nighters as a student
and for about 13 years professionally :)  Actually,
it  sounds like I may be learning some VB and I'm
hoping that  it's a bit less "forgiving" about messy
programming.

Thanks again.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
..well...my compiler doesn't complain when I mx int and char.

Strange.

I think I see what part of our problem is. At some point (years ago), it seems someone ran a program that read through
our source code and "automatically" generrated a whole
slew of prototypes to a file functions.h. This approach,
however,  seems to have had serveral problems including
duplicating protos already defined within C files, and
"mangling" types.
E.g.
char somehow becomes unsigned char

uint_16 (which we typdef as unsigned short) becomes unsigned short

FILE* becomes struct __iobuf*

etc.

I'll tell you, if I were an IT manager (which I'm not) and
was seeing a project from the ground up, I would rigidly
enforce prototyping EVERY function...saves so much
pain down the road :)

Thanks.
OK, I think I have enough info for now. Thanks!!
Efn,
Hi. Sorry to re-open this one, but I just hit a living, breathing
example of a prototype "conflict" if you will in my system.

Here, int's are 32-bit and int_16 is a signed short.

// in FUNCTIONS.H
int_16 GetAmount(int_16 flag);

In the actual C file
int_16 GetAmount(int flag)

How much trouble (if any) will this inconsitency cause
(or for that matter the opposite case). FYI: the function
is called as follows:
GetAmount(TRUE);
(or)
GetAmount(FALSE);
where FALSE is 0 and TRUE is 1

I've fixed this already, but I'm concerned that there may
be a few other such inconsistincies I've yet to find.

I sure wish my compiler would have caught that....
Thanks.
PS-Since  I have in effect re-opened this question, I will
see if the mods can do something so I can award more
points.

Steve
I don't think it will cause any trouble at all, because, as I think I mentioned before, integral types smaller than int automatically get promoted to int when passed to a function.  This may be why your compiler didn't bother to hassle you about the inconsistency.  If you were dealing with values that would not fit in an int_16, you might have trouble, but 0 and 1 should be fine.  That is, no matter which declaration is in effect at the point of the function call, the value will be passed as an int, and whichever way the function is defined, it will expect to get an int.
Thanks.

..and I assume the same would apply for:

* the opposite case where the proto was int and
the def'n int_16?

* where the proto is char and the def'n int?

* where the proto is int and the def'n char?

I'm hoping you say it does (although feel free to be
brutally honest and say it does not :) Let me tell
you what I'm facing at this point. We're in the throes
of an upgrade from a 16-bit to 32-bit application,
meaning that in the "good old days" int and int_16
were both 2-byte integers (and for unsigned's,
unsigned int and uint_16 are both 2-byte integers).

Now, of course,  int and unsigned int is 4 bytes, and
I'm  concerned about cases where you have the
type conflict mentioned above. Of course, I realize that
for values that a 16-bit# can't hold you might get in trouble,
but I'm pretty confident that the nature of the data
precludes such problems: if these values "needed" to
exceed 16-bit, we would have received bug reports
from customers using the DOS build.

So, I've been laboriously going through our major
C files, looking for missing or inconsisent prototypes,
having reviewed over 40 files already...you get the picture :)?

Thanks.






Yes, I think what I said also applies in these cases.

You could run into trouble in any of these cases if you have signed-unsigned mismatches in the parameter declarations and negative numbers as argument values.  For example, 0xFFFF declared as signed and promoted to a 32-bit int is 0xFFFFFFFF, but if it's declared unsigned, it's promoted to 0x0000FFFF.

You're welcome.
Thanks.

Once I purchase more points (within the next week or so), I will be posting a "points for" question
(as per what I was told in Community Support), so I can assign more points to you.

stevefromc
Efn,
No I found another one...we acutally seem to have 2 H files that have function prototypes  and,
not surprisingly I found something like:

in DECLARE.H
iint_16 some_function(char *buff, int_16 flag, void *voidptr);

in FUNCTIONS.H (which is processed AFTER declare.h)
iint_16 some_function(char *buff, int flag, void *voidptr);

Funciton def'n
iint_16 some_function(char *buff, int flag, void *voidptr)

What happens here with the two different PROTOTYPES?
Thanks

The same thing:  if the compiler sees both, it should complain, but your compiler probably won't, possibly because int_16 gets promoted to int.

The general topic here is compatibility of function types.  You can read about it on these pages:

http://osr507doc.sco.com/en/topics/ComplStdC_CompatFuncTypes.html

http://publib.boulder.ibm.com/infocenter/macxhelp/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc07funcdef.htm

and down at the bottom of this page:

http://www-ccs.ucsd.edu/c/types.html