views:

83

answers:

3

Hello, I am new to programming, I've done web development, but I am currently trying to learn real programming. The question I have is already answered here.

union ufloat {
  float f;
  unsigned u
};

ufloat u1;
u1.f = 0.3f;

What I don't get is how it works. What does the 0.3 part do? I couldn't find it in my text. And how does this convert a float to binary? Because cout<<u1.u; doesn't seem to give me the answer. Can someone help?

+1  A: 

0.3 is just a test value. Printing u1.u will not give you the binary representation, but the value of the binary representation interpreted as a base 10 integer. To get the binary value, you have to convert u1.u to binary.

Another way you can do the conversion is by using bitwise operators.

For example:

unsigned x = 11;
do
{
    cout << (x & 1); // print last bit
    x = x >> 1; // get rid of the printed bit
} while ( x );

Note that this will print the bits in reverse order (least significant first). I'll leave it up to you to fix this (you can use recursion or store values in an array and then print the array reversed).

I also suggest you read about unions. Basically, the unsigned will occupy the same memory space as the float, allowing you to circumvent the restrictions of using bitwise operators to find the binary representation of the float.

IVlad
It's kinda cheap to "leave as an exercise" the way to print bits in the right order. Dude here probably wants answers more than exercises.
zneak
@zneak - since he is already dealing with unions, I think it's safe to assume he also knows what arrays are, and maybe even recursion, in which case my short explanation will be more than enough. If this is not the case, that's what comments are for: he can tell me and I can improve my post. The question seems to be more about how the the union "magic" works than how to convert an integer to binary.
IVlad
Yes, thank you.
Btw, it's usually easier to read hex than binary (binary strings are very long and monotonous). Unless you have a specific requirement for a binary string, `std::cout << std::hex << x;` is more concise than a lot of bit-twiddling, and still shows you the representation of the float.
Steve Jessop
A: 

The answers lies in how unions work in C/C++. A union allows you to represent multiple types of data using the same space in memory. So in your example, the ufloat union stores the float and the integer in the same memory space. Depending on how you access this memory space, (either via the f data member or the u data member), the program will interpret the memory region as either a float or an unsigned integer respectively.

When you access the memory region via the u data member, the program thinks you want to represent the memory region as a binary integer, rather than a floating point value. But since the memory region is actually storing a floating point value (0.3f), it simply outputs this value as if it was a binary integer. Thus, you get your binary representation of the float.

Charles Salvia
+1  A: 

To be excessively pedantic, that's not valid C or C++.

I suspect that every compiler in existence supports it, but as far as the standard is concerned, it's not valid to write one member of a union and then read another. However, to even know that float and unsigned are the same size you're already using some implementation-defined information, so you may as well use more. It's common and it generally works.

For reference, though, you can always examine memory as a series of bytes:

#include <iostream>
#include <iomanip>
#include <climits>
#include <cassert>

int main() {
    float f = 0.3;
    unsigned char *buf = (unsigned char*)(&f);

    // Now we just have to print the sucker.

    assert(CHAR_BIT == 8); // otherwise hex isn't much use

    // This shows the byte representation, low addresses on the left.
    // On a little-endian machine, you might like to count down for 
    // convenience of reading.
    for (int i = 0; i < sizeof f; ++i) {
        std::cout << std::hex << std::setw(2) << std::setfill('0');
        std::cout << static_cast<unsigned int>(buf[i]) << ' ';
    }
    std::cout << '\n';
}

Output (on my machine):

9a 99 99 3e

If you do prefer to use unsigned rather than unsigned char:

#include <cstring>

float f = 0.3;
unsigned u;
assert(sizeof f == sizeof u);
std::memcpy(&u, &f, sizeof f);

std::cout << std::hex << u << "\n";

Output (on my machine):

3e99999a
Steve Jessop