0

Is the output correct for the following programs? I am using a Cygwin64 GCC compiler on a X86_64 Windows system. The architecture is little endian.

#include <stdio.h>

int main(int argc, char *argv[])
{
    int i = 0;
    float floatVal = 0x12345678;
    do
    {
        printf("Hello World %f\n", floatVal);
        floatVal++;
        i++;
    } while ( i < 10 );
    return 0;
}

Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000
Hello World 305419904.000000

Question 1: However this website gives me a completely different answer: http://www.binaryconvert.com/result_float.html?hexadecimal=12345678

Question 2: Why is the value not incrementing? The increments happen however if I use double instead of float.

What am I doing wrong?


Edit, after getting the correct answers:

After getting the correct answers from unwind, I have a further question and to do the same in Java. Since Java, does not use unions, is there a way to do the conversion from integer to float the same way as the accepted answer in C. I found the answer here :

How can I get/set individual bits in a float?

Community
  • 1
  • 1
infoclogged
  • 3,641
  • 5
  • 32
  • 53
  • 2
    You're confused between the hex *value* of an integer literal (which gets converted to a float) and the hex *representation* of a float. `0x12345678` == `305419904`. – Paul R Nov 18 '15 at 10:35

2 Answers2

4

You're expecting the integer literal (0x12345678) to be used to set the bits of the float, but that isn't what happens.

Instead you get the actual integer (0x12345678 is 305419896 in decimal); your code is exactly the same as if it had said

float floatVal = 305419896;

The hexadecimal number is just an integer, that it's hex has no special meaning.

To do what you want, you'd to use an actual hexadecimal float constant perhaps, but that's a bit complicated.

You can use a union to the bits in there:

const union {
 int integer;
 float real;
} pair = { .integer = 0x12345678 };
float floatVal = pair.real;

Note that the above is undefined if the sizes mismatch, and also (as you seem to be aware) endian-specific.

If you print using %e or %g you will get the result you expect:

printf("%g\n", floatVal);

prints 5.69046e-28 on ideone.com.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • That's undefined even if the sizes match. There's no guarantee that you can reference an `int` as a `float` by casting the address. See http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – Andrew Henle Nov 18 '15 at 10:44
  • 1
    @AndrewHenle Thanks. Changed it to use a union instead which afaik should be OK. – unwind Nov 18 '15 at 11:11
  • @unwind can you please also write the answer when you print floatVal? – infoclogged Nov 18 '15 at 11:33
  • @unwind Using a union is also technically undefined behavior. The one and only standard-compliant way to reinterpret data like this is with `memcpy`. – Sneftel Nov 18 '15 at 11:58
  • @Sneftel Footnote 82 of C99TC3 makes using a union sound more like implementation-defined behavior, though. – Pascal Cuoq Nov 18 '15 at 15:06
2

Firstly you're confused between the hex value of an integer literal (which gets converted to a float) and the hex representation of a float. 0x12345678 == 305419904.

As for the increment of a float using ++ seemingly not working as expected - this is simply due to the finite precision of a single precision floating point representation. If you start with a smaller number then you will see the expected behaviour:

 float f = 1.0f;  // f = 1.0
 f++;             // f = 2.0

However in your example:

 float f = 305419904.0f;  // f = 305419904.0
 f++;                     // f = 305419904.0

Note that using double will give the correct result for this case:

 double g = 305419904.0;  // g = 305419904.0
 g++;                     // g = 305419905.0
Paul R
  • 208,748
  • 37
  • 389
  • 560