Reputation: 45
Two questions regarding this simple code:
float foo(){
return 128.0;
}
int main(){
char x = (char) 128;
char y = (char) 128.0;
char z = (char) foo();
printf("x: %d \ny: %d \nz: %d", x, y, z);
}
My output:
x: -128
y: 127
z: -128
Why is 128.0 prevented from overflowing when converted to a char
and why isn't it when it's the return-value of a function rather than a literal? I'm happy to really get into detail if an adequate answer requires it :)
(I'm using gcc-4.8.1 and don't use any options for compiling, just gcc file.c)
Upvotes: 1
Views: 73
Reputation: 67476
result of y
is an Undefined Behaviour
As you see different compilers give different results.
z
is also an Undefined Behaviour but without optimisations enabled even this very trivial example is evaluated. But if you enable optimizations the result of will the same (because compiler chooses the result).
Upvotes: 2
Reputation: 222302
Your C implementation appears to have a signed eight-bit char
type. 128 cannot be represented in this type.
In char x = (char) 128;
, there is a conversion from the int
value 128 to the char
type. For this integer-to-integer conversion, C 2018 6.3.1.3 3 says:
Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
“Implementation-defined” means a conforming C implementation is required to document how it behaves for this conversion and must abide by that. Your implementation apparently wraps modulo 256, with the result that converting 128 to char
produces −128.
In char y = (char) 128.0;
, there is a conversion from the double
value 128 to the char
type. For this floating-point-to-integer conversion, C 2018 6.3.1.4 2 says:
If the value being converted is outside the range of values that can be represented, the behavior is undefined.
“Undefined” means the C standard does not impose any requirements; a C implementation does not have to document its behavior and does not have to abide by any particular rules. In particular, the behavior may be different in different situations.
We see this in that char y = (char) 128.0;
and char z = (char) foo();
produced different results (127 and −128). A common reason for this is that, since a constant is used, the compiler may have evaluated (char) 128.0
itself using internal software that clamps out-of-range results to the limits of the type, so the out-of-range 128 resulted in the maximum-possible 127, and y
was initialized to that. On the other hand, for char () foo()
, the compiler may have generated instructions to perform the conversion at run-time, and those instructions behaved different from the internal compiler evaluation and wrapped modulo 256, producing −128.
Since these behaviors are not specified by the C standard or, likely, your compiler’s documentation, you should not rely on them.
Upvotes: 2