If I have a function, say
void f(int a, char b);
And I call this function with the following arguments
char a;
int b;
f(a, b)
In this and similar cases of passing an argument without typecasting, what
does the C standard say about implicit typecasting in these cases?
As long as there is a prototype in scope, any function call is
semantically equivalent to a sequence of assignments (in no
definable order, perhaps even all simultaneous) to the parameters
to that function:
void f(int, char);
void somefunc(void) {
f(3.14159, 2.71828);
}
means exactly the same thing as:
void somefunc(void) {
f(3, 2);
}
since assigning 3.14159 to an "int" sets that int to 3, and
assigning 2.71828 to a "char" sets that char to 2.
If a prototype is *not* in scope, the actual arguments undergo
the default argument promotions; if the resulting types do not
match the actual formal parameter types[%], the behavior is
undefined. Thus, without a prototype for f(), passing "3.14159"
would pass a double to a function that needs an int, resulting
in undefined behavior. But even:
/* no prototype in scope for f() */
f(3, 2);
or:
/* no prototype in scope for f() */
f(3, (char)'x');
would result in undefined behavior, because f()'s second parameter
must have type "char", and 2 is an int. The second might "look
right", but while (char)'x' is in fact a char, it becomes an int
(or possibly an unsigned int) under the default argument promotions.
-----
[%] The formal parameter types may also undergo promotion if the
function is defined using an old-style K&R definition. That is:
int f(a, b) int a; char b; { ... }
has as its correct prototype:
int f(int, int); /* or possibly int f(int, unsigned int); */
One should always use prototypes in modern C, so as to avoid this
sort of difficult-to-analyze situation.