Is this code undefined behavior?
extern long f(long x);
long g(int x)
{
return f(x);
}
According to the C11 standard, in 6.5.2.2 §6:
If the function is defined with a type that includes a prototype, and [...] the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.
In the example above, the function f
is defined with a type that includes a prototype and the type of the argument x
is int
while the type of the parameter x
is long
. According to 6.2.7 §1:
Two types have compatible type if their types are the same.
Therefore, long
and int
are not compatible, so the behavior is undefined, right?
However, in 6.5.2.2 §7:
If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type.
If I correctly understand this paragraph, it means the argument x
which is of type int
is implicitly converted to long
when the function is called. According to 6.3.1.3 §1:
When a value with integer type is converted to another integer type other than
_Bool
, if the value can be represented by the new type, it is unchanged.
As int
has a lower rank than long
, every int
variable can be represented by a long
variable. Therefore, the argument x
can be converted into a long
. Therefore, this is not undefined behavior.
Which interpretation of the standard is right? Is my code undefined behavior or not?
You provided irrelevant quotes relative to your code snippet. According to the same section (6.5.2.2 Function calls)
2 If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
The function f
has a prototype that is visible in the call expression
extern long f(long x);
and this assignment
int argument;
long parameter;
parameter = argument
is correct.
As for this quote
6 If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined. 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:
Then it means the following. The function calling expression does not see the function prototype. So the default argument promotions are performed. But somewhere else the function is defined with a function prototype and the promoted arguments are not compatible with function parameters. In this case you will have undefined behavior.
Here is a demonstrative program with undefined behavior related to a function call. The compiler can issue an error message.
#include <stdio.h>
void f();
int main(void)
{
short x = 10;
f( x );
return 0;
}
void f( char *s )
{
printf( "s = %s\n", s );
}
or
#include <stdio.h>
#include <limits.h>
void f();
int main(void)
{
unsigned int x = UINT_MAX;
f( x );
return 0;
}
void f( int x )
{
printf( "x = %hd\n", x );
}
For example in the last program the argument x
in the call expression
f( x );
is promoted to the type unsigned int
. But according to the function definition the function expects an argument of the type signed int
and the passed value can not be stored in the type signed int
. So the behavior is undefined.
But your original example of a function call is not related to this quote.