I have a question about default argument promotions in C99 standard. In the book "C Programming - A Modern Approach, 2nd Edition" I've read that:
Argument Conversions:
[...]
1) The compiler has encountered a prototype prior to the call. [...]
2) The compiler has not encountered a prototype prior to the call. The compiler performs the default argument promotions: (1)
float
arguments are converted todouble
. (2) The integral promotions are performed, causingchar
andshort
arguments to be converted toint
. (In C99, the integer promotions are performed.)
A few lines further is shown an example in which there is no function prototype or definition before calling it. It is commented as follows:
Of course, a much better solution is to provide a prototype for
square
before calling it. In C99, callingsquare
without first providing a declaration or definition of the function is an error.
Aren't those two cursive sentences kind of contrary with each other? I mean, if C99 forbids calling functions without previous declaration/definition how can it determine promotions in that kind of function call?
No they are not contradictory.
A declaration is not necessarily a prototype:
int f();
declares the function f
but isn't a prototype since nothing is known about the argument types.
int (a)
in a;
{
...
}
is a definition but isn't a prototype either.
C99 does not forbid you to call functions that have no prototype.
I can't give the details because you have not posted code for square()
or the call to it, but presumably what is happening is that the promotion made to the arguments in the call to square()
result in different types being passed to the function than it actually declares in the implementation.
That's what would result in undefined behavior, and would be an error.
For example:
// in foo.c:
int foo(void)
{
char x = 42;
return square(x); // x is promoted to int, but is wrong
}
// in bar.c
#include <stdio.h>
void bar(int x)
{
square( &x); // this call is fine - what is being passed is what square() expects
printf("The result is %d\n", x);
}
// in square.c
void square( int* p)
{
*p *= *p;
return;
}
And if square()
is defined with a prototype that declares the parameter to have an argument of type char
, there's no way to call correctly it without a prototype having been 'seen' by the calling code since in such cases the argument will be promoted to int
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With