views:

47

answers:

2

I read about unions the other day( today ) and tried the sample functions that came with them. Easy enough, but the result was clear and utter garbage.

The first example is:

union Test
{ 
    int Int;

    struct
    {
        char byte1;
        char byte2;
        char byte3;
        char byte4;
    } Bytes;
};

where an int is assumed to have 32 bits. After I set a value Test t; t.Int = 7; and then cout

cout << t.Bytes.byte1 << etc...

the individual bytes, there is nothing displayed, but my computer beeps. Which is fairly odd I guess.

The second example gave me even worse results.

union SwitchEndian
{
    unsigned short word;

    struct
    {
        unsigned char hi;
        unsigned char lo;
    } data;
} Switcher; 

Looks a little wonky in my opinion. Anyway, from the description it says, this should automatically store the result in a high/little endian format when I set the value like

Switcher.word = 7656; and calling with cout << Switcher.data.hi << endl

The result of this were symbols not even defined in the ASCII chart. Not sure why those are showing up.

Finally, I had an error when I tried correcting the example by, instead of placing Bytes at the end of the struct, positioning it right next to it. So instead of

struct {} Bytes;

I wanted to write

struct Bytes {};

This tossed me a big ol' error. What's the difference between these? Since C++ cannot have unnamed structs it seemed, at the time, pretty obvious that the Bytes positioned at the beginning and at the end are the things that name it. Except no, that's not the entire answer I guess. What is it then?

+3  A: 

The beeps and weird symbols are because you are trying to print the character representations of decimal numbers, in this case, ASCII control characters. In your first example (the beeps), you are printing ASCII 7 which is the bell character.

You can cast your data to int to print out the actual decimal representation, e.g.:

cout << (int)t.Bytes.byte1 << endl << (int)t.Bytes.byte2 << endl << (int)t.Bytes.byte3 << endl << (int)t.Bytes.byte4 << endl;

You can do something similar for your second example to see the decimal representation of those unsigned char values in memory.

The reason for the difference is that the type of cout, basic_ostream, has multiple overloads for operator<< for various basic types.

For your last issue, what compiler error are you getting? Both struct definitions compile fine for me when using VS2008.

Chris Schmich
+2  A: 

Note that, technically, reading from a member of a union other than the member that was last written to results in undefined behavior, so if you last assigned a value to Int, you cannot read a value from Bytes (there's some discussion of this on StackOverflow, for example, in this answer to another question).

Chris Schmich gives a good explanation of why you are hearing beeps and seeing control characters, so I won't repeat that.

For your final question, struct {} Bytes; declares an instance named Bytes of an unnamed struct. It is similar to saying:

struct BytesType {};
BytesType Bytes;

except that you cannot refer to BytesType elsewhere. struct Bytes {}; defines a struct named Bytes but declares no instances of it.

James McNellis