Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 298
  • Last Modified:

implict prototype determined when passing function to another function?

Hello all.
This question is somewhat related to

http://www.experts-exchange.com/Programming/Programming_Languages/C/Q_21377175.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 :)


0
Stephen Kairys
Asked:
Stephen Kairys
  • 9
  • 7
3 Solutions
 
efnCommented:
Strictly speaking, a compiler does not construct or generate prototypes.  It has an idea of what parameters a function requires, which can change as it sees different declarations, as you saw in your last question.  I assume that is what you are referring to as an implicit prototype.

In this case, when you declare display_zipcode_data with an empty parameter list, the compiler figures anything goes, and you are responsible for making the function make sense of whatever is passed to it.  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.  Similarly, if you pass a pointer to the display_zipcode_data function to another function, the compiler assumes you know what you are doing and does not draw any new conclusions about the parameters of display_zipcode_data.
0
 
NovaDenizenCommented:
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) {
}

0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
>>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
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
efnCommented:
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.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
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
0
 
efnCommented:
It will be an int.

There isn't really an argument.  When the compiler generates code for the calling function, it see that anything goes as an argument to foo.  (I'm assuming it hasn't seen the declaration or definition of foo as taking a char.)  So it generates code that passes an int, as specified by the programmer.  At that point, it has no idea that somewhere else there floats a specification that foo takes a char, and it doesn't go search the universe to find out if there is.

To illustrate with a goofy pseudocode analogy:

void readmail();

ScrambledEgg se;

readmail(se);

void readmail(Letter missive)
{
  read missive;
}

The compiler will obediently pass the ScrambledEgg to the readmail function, which will treat it as though it were a Letter.  This is unlikely to be useful.  But that's what you get for being a big shot and declaring readmail without parameters, telling the compiler, "Don't worry, I know what I'm doing."  Or, one might say, that's what you get for using C, which lets you get away with such shenanigans.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
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.
0
 
efnCommented:
> I guess the same thing would apply here, right?

It depends.  If the first prototype and the function definition are in separate translation units, so the compiler doesn't know about the first one when it sees the second one, then, yes, it would be a mismatch as in the previous case.

If they are in the same translation unit, then what happens depends on whether ScrambledEgg and Letter are compatible types.  If not, the compiler should generate an error message.  In the original example, int and char are not compatible types, so if both declarations of foo are visible, the compiler should complain.  When I tried it, I just got a warning from Visual C++ 6.

If the types are compatible, they define a composite type, and it works as if the parameter were declared with the composite type.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
..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.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
OK, I think I have enough info for now. Thanks!!
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
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
0
 
efnCommented:
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.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
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.






0
 
efnCommented:
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.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
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
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
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

0
 
efnCommented:
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
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now