Hello,
I think I've mostly understood this section but the last part is still
obscure for me.
Here is what it says:
If the function is defined with a type that does not include a
prototype,
and the types of the arguments after promotion are not compatible
with those of the parameters after promotion, the behavior is
undefined, except for the following cases:
[...]
I fail to understand "parameters after promotion". I thought that
promotions were applied to arguments only (not parameters).
So here is a definition without prototype:
void foo(a, b, c) { return; }
I thought that type of parameters default to int, so there's no need
for promotions here.
Could anybody shed some light here ?
Consider:
#include <stdio.h>
float f = 3.14159;
printf("%g\n", f);
The type of f is float, but it will be promoted to double.
As an example, consider this question from the C-FAQ:
12.9: Someone told me it was wrong to use %lf with printf(). How can
printf() use %f for type double, if scanf() requires %lf?
A: It's true that printf's %f specifier works with both float and
double arguments. Due to the "default argument promotions"
(which apply in variable-length argument lists such as printf's,
whether or not prototypes are in scope), values of type float
are promoted to double, and printf() therefore sees only
doubles. (printf() does accept %Lf, for long double.)
See also questions 12.13 and 15.2.
References: K&R1 Sec. 7.3 pp. 145-47, Sec. 7.4 pp. 147-50; K&R2
Sec. 7.2 pp. 153-44, Sec. 7.4 pp. 157-59; ISO Sec. 7.9.6.1,
Sec. 7.9.6.2; H&S Sec. 15.8 pp. 357-64, Sec. 15.11 pp. 366-78;
CT&P Sec. A.1 pp. 121-33.
and similarly:
15.2: How can %f be used for both float and double arguments in
printf()? Aren't they different types?
A: In the variable-length part of a variable-length argument list,
the "default argument promotions" apply: types char and
short int are promoted to int, and float is promoted to double.
(These are the same promotions that apply to function calls
without a prototype in scope, also known as "old style" function
calls; see question 11.3.) Therefore, printf's %f format always
sees a double. (Similarly, %c always sees an int, as does %hd.)
See also questions 12.9 and 12.13.
References: ISO Sec. 6.3.2.2; H&S Sec. 6.3.5 p. 177, Sec. 9.4
pp. 272-3.
And even a bit more esoteric:
15.10: I have a varargs function which accepts a float parameter. Why
isn't
va_arg(argp, float)
working?
A: In the variable-length part of variable-length argument lists,
the old "default argument promotions" apply: arguments of type
float are always promoted (widened) to type double, and types
char and short int are promoted to int. Therefore, it is never
correct to invoke va_arg(argp, float); instead you should always
use va_arg(argp, double). Similarly, use va_arg(argp, int) to
retrieve arguments which were originally char, short, or int.
(For analogous reasons, the last "fixed" argument, as handed to
va_start(), should not be widenable, either.) See also
questions 11.3 and 15.2.
References: ISO Sec. 6.3.2.2; Rationale Sec. 4.8.1.2; H&S
Sec. 11.4 p. 297.