简体   繁体   中英

is using a constant without an explicit cast invoke undefined behavior?

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? 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 ??

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.

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.

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.

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM