Reputation:
Upon invoking a function,or returning a value from a function,that expects a value of type T
,does using a constant literal without explicit cast invoke undefined behavior?
For example,we have a function who's prototype is long foo(unsigned long x);
Invocation: foo(4); //does this invoke UB?
long foo(unsigned long x) { x += 10; return 10; } // does this invoke UB ?
should we write foo((unsigned long)4)
and return (long)10
??
Upvotes: 1
Views: 120
Reputation: 37944
No, it wouldn't make sense, since such argument is passed by value in both C and C++:
long foo(unsigned long x);
You may think of it technicaly as x
parameter is a local automatic variable defined inside foo
and assigned with the value of passed argument:
unsigned long x = 4;
If type of argument does not match with parameter, then compiler tries with implicit conversion. For instance, an argument of type double
is silenty converted into of type unsigned long
, even it means loss of information (you might get a compiler warning though).
You may however get into trouble, when you mark type of x
parameter as reference (C++ only):
long foo(unsigned long& x);
Here, the compiler would not allow you to call it as foo(4)
, because you are now passing by reference, and 4
cannot be modified as such. You may however pass it if the parameter is marked with const
qualifier:
long foo(const unsigned long& x);
Upvotes: 0
Reputation: 141628
Consider this C code:
// foo.c
int foo(unsigned long x) { }
and
// main.c
int foo();
int main()
{
foo(4); // UB
foo((unsigned long)4); // OK
}
The foo(4)
call is UB because when you are calling a function with no prototype in scope, you must manually make sure the parameters match. The default argument promotions occur but that's all.
Of course, writing the cast is a bad solution from the point of view of writing robust code. The better solution would be to write a prototype:
int foo(unsigned long);
in a header file which is included from both the .c
files.
The return 10;
case can never be UB because the function's true return type is known to the compiler when it is compiling the code inside the function body.
Upvotes: 0
Reputation: 15229
No, it is all well-defined.
There exists an implicit conversion rule between the two types, so the int
is simply converted to an unsigned long
and the program works as expected.
Upvotes: 6
Reputation: 30489
Type of literal 4
is int
. (In C section 6.4.4.1 Integer constants, similar section available in C++ also)
Implicit conversion from int
to unsigned long
is well defined in both C and C++. (In C section 6.3.3.1)
should we write foo((unsigned long)4) and return (long)10?
Both of your example are well defined, so this conversion though acceptable is superfluous.
Upvotes: 3