Kroszi
Kroszi

Reputation: 45

Weird results with type conversion of literals and return values in C

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

Answers (2)

0___________
0___________

Reputation: 67476

result of y is an Undefined Behaviour

https://godbolt.org/z/3x68ze

enter image description here 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).

enter image description here https://godbolt.org/z/WaPE4r

Upvotes: 2

Eric Postpischil
Eric Postpischil

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

Related Questions