I have a few questions about the default argument promotions when calling a function in C. Here\'s section 6.5.2.2 \"Function calls\" Paragraphs 6, 7, and 8
Upvoted AProgrammer's answer—those are the real goods.
For those of you who are wondering why things are this way: in the dark ages before 1988, there was no such thing as a function prototype in classic "K&R" C, and the default argument promotions were instituted because (a) there were essentially "free", as it costs no more to put a byte in a register than to put a word in a register, and (b) to cut down on potential errors in parameter passing. That second reason never quite cut it, which was why the introduction of function prototypes in ANSI C was the single most important change ever in the C language.
As to when default promotions kick in: default argument promotions are used exactly when the expected type of the argument is unknown, which is to say when there's no prototype or when the argument is variadic.
Your confusion stems from a very slight misunderstanding of the terminology - both declarations and definitions can include prototypes (or not):
void func(int a, char b, float c);
That is a function declaration that includes a prototype.
void func(int a, char b, float c) { /* ... */ }
That is a function definition that includes a prototype.
"Prototyped" and "non-prototyped" are just attributes of a function type, and both declarations and definitions introduce the type of the function.
So you can have a declaration without a prototype:
void func();
or you can have a definition without a prototype (K&R C style):
void func(a, b, c)
int a;
char b;
float c;
{ /* ... */ }
(Non variadic) parameters to functions with a prototype are converted to the corresponding type, which can be char, short, float.
Parameters to functions without prototype and variadic parameters are subject to default argument promotions.
If you define a function with a prototype and use it without the prototype or vise versa and it has parameters of type char, short or float, you'll probably have a problem at run-time. You'll have the same kind of problems with variadic functions if the promoted type doesn't match what is used when reading the argument list.
Example 1: problem when defining a function with a prototype and using it without.
definition.c
void f(char c)
{
printf("%c", c);
}
use.c
void f();
int main()
{
f('x');
}
can fail because an int will be passed and the function expect a char.
Example 2: problem when defining a function without a prototype and using it with one.
definition.c
void f(c)
char c;
{
printf("%c", c);
}
(This is kind of definition is very old fashioned)
use.c
void f(char c);
int main()
{
f('x');
}
can fail because an int is expected but a char will be passed.
Note: you'll remark that all functions from the standard library have types which result from default promotions. So they didn't cause problem during the transition when prototypes were added.