Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the behaviour of casting a negative double to unsigned int defined in the C standard? Different behaviour on ARM vs. x86

I have code that runs on different platforms that seems to get different results. I am looking for a proper explanation.

I expected casting to unsigned to work the same for float or double as for int1.

Windows :

double dbl = -123.45;  int d_cast = (unsigned int)dbl;  // d_cast == -123 

WinCE (ARM):

double dbl = -123.45;  int d_cast = (unsigned int)dbl;  // d_cast == 0 

EDIT:

Thanks for pointing in the right direction.

fix workaround

double dbl = -123.45;  int d_cast = (unsigned)(int)dbl;  // d_cast == -123 // works on both.  

Footnote 1: Editor's note: converting an out-of-range unsigned value to a signed type like int is implementation defined (not undefined). C17 § 6.3.1.3 - 3.

So the assignment to d_cast is also not nailed down by the standard for cases where (unsigned)dbl ends up being a huge positive value on some particular implementation. (That path of execution contains UB so ISO C is already out the window in theory). In practice compilers do what we expect on normal 2's complement machines and leave the bit-pattern unchanged.

like image 673
corn3lius Avatar asked May 10 '12 19:05

corn3lius


1 Answers

No


This conversion is undefined and therefore not portable.

C99/C11 6.3.1.4

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.

According to C11 6.3.1.4 footnote 61:

The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).

like image 105
DigitalRoss Avatar answered Oct 22 '22 07:10

DigitalRoss