From The C Programming Language 2nd Edition:
Since an argument of a function call is an expression, type conversions also take place when arguments are p
Casts are irrelevant, it's the (possibly implicit) prototype that matters.
void foo(short s) {
// do something
}
int main(void) {
signed char c = 'a';
foo(c); // c is promoted to short by explicit prototype
bar(c); // c is promoted to int by implicit prototype
}
void bar(int i) {
// do something
}
When the book says "an argument of a function call is an expression" it means that the same type promotion rules apply. It might be easier to understand if you think of a function argument as an implicit assignment to the variable specified in the function prototype. e.g. in the call to foo() above there's an implicit short s = c.
This is why casts don't matter. Consider the following code snippet:
signed char c = 'a';
int i = (short) c;
Here the value of c is promoted first to short (explicitly) then to int (implicitly). The value of i will always be an int.
As for char and short becoming int and float becoming double that refers to the default types for implicit function prototypes. When the compiler sees a call to a function before it has seen either a prototype or the definition of the function it generates a prototype automatically. It defaults to int for integer values and double for floating-point values.
If the eventual function declaration doesn't match to implicit prototype, you'll get warnings.