10

Please have a look at this code:

#include <stdio.h>

int main(void)
{
    short s;
    int i = 65696;
    float f = 65696.0F;

    printf("sizeof(short) = %lu\n", sizeof(short));

    s = i;
    printf("s = %hd\n", s);
    s = f;
    printf("s = %hd\n", s);

    s = 65696;
    printf("s = %hd\n", s);
    s = 65696.0F;
    printf("s = %hd\n", s);

    return 0;
}  

It gave output as :

sizeof(short) = 2
s = 160
s = 160
s = 160
s = 32767

In last line why it's 32767 and not 160 ? What's the difference between saying f = 65696.0F; s = f; and s = 65696.0F; ?

eandersson
  • 25,781
  • 8
  • 89
  • 110
rootkea
  • 1,474
  • 2
  • 12
  • 32

2 Answers2

13

Because if the integral part of the float value is not representable in the new type, the conversion is undefined behavior.

In your case, SHRT_MAX is probably 32767 and so the integral part of 65696.0F is then not representable in a short object.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 7
    +1. Specifically, 6.3.1.4/1: *"When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined)"* – Jon Feb 08 '13 at 14:21
  • @Jon So why not same thing happening when I say `f = 65696.0F; s = f` ? – rootkea Feb 08 '13 at 14:22
  • 3
    @rootkea this is undefined behavior as well and yeah undefined behavior can be unpredictive. – ouah Feb 08 '13 at 14:24
  • @Jon By 'finite value' do you mean 'a constant' ? – rootkea Feb 08 '13 at 14:29
  • @rootkea no, it means neither infinities nor NaN. – ouah Feb 08 '13 at 14:30
  • @ouah Then why not behaviour is undefined when I say `s = f` ? – rootkea Feb 08 '13 at 14:33
  • 3
    @rootkea It's still undefined behavior. It just happens to return `160` in your particular case. – Mysticial Feb 08 '13 at 14:34
  • [Info about undefined behavior](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) (C and C++ have identical meanings of these terms). – Lundin Feb 08 '13 at 14:42
2

This is "undefined behaviour," which means that the compiler is free to do what it wants. But "undefined" does not mean "unexplainable."

What the compiler is doing in the case of s = f is converting f first to the int value 65696, and then assigning 65696 to s, which overflows and leaves 160. The compiler does this because there is a CPU instruction to convert a floating point number into a 32-bit integer, but not directly into a 16-bit integer

What the compiler is doing with s = 65696.0F is simpler: It knows that 65696.0 is out of range, so it assigns the highest value available to s, which happens to be 2^15-1 = 32767.

You can verify this if you read the assembly code the compiler generates for s = f (for example using -S switch with gcc):

    movss   -4(%rbp), %xmm0        # Load float from memory into register xmm0
    cvttss2si       %xmm0, %eax    # Convert float in xmm0 into signed 32 bit, store in eax
    movw    %ax, -10(%rbp)         # Store lower 16 bits of eax into memory
    movswl  -10(%rbp), %eax        # Load those 16 bits into eax, with sign extend

The last instruction clobbers the high 16 bits of %eax, setting it to all 0s in this case.

What it generates for s = 65696.0F is simpler:

    movw    $32767, -10(%rbp)      # Store the lower 16 bits of 32767 into memory
    movswl  -10(%rbp), %eax        # Load those 16 bits into eax, with sign extend
Joni
  • 108,737
  • 14
  • 143
  • 193