A question about union

Hello!
I have recently read a section of a book about struct and union. They say that you can access the 4 bytes of a [unsigned] long int variable through a union. So, I thought reading the individual bits of the variable would also be possible. I put together this test code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <iostream>
using namespace std;
int main(){
  typedef union{
    unsigned long int triplet;
	unsigned char color[4];
  }hexTriplet;
  typedef union{
    unsigned long int value;
	bool bits[32];
  }Dword; //LSB first
  enum{BLUE, GREEN, RED};
  hexTriplet colour;
  Dword num;
  colour.triplet = 0xFF7799; //255, 119, 153 (16,742,297)
  num.value = 1431655765; //0101 0101 0101 0101 0101 0101 0101 0101
  printf("Triplet: %d\n", colour.triplet);
  printf("Red: %d\nGreen: %d\nBlue: %d\n", colour.color[RED], colour.color[GREEN], colour.color[BLUE]);
  printf("Dword: %d\nBits: ", num.value);
  for(int i = 31; i >= 0; i--){ //does not work
    cout << num.bits[i];
	if ((i+1)%4 == 0 && i != 31) cout << " ";
  }
  return 0;
}


This is the output on Windows Command Prompt:
1
2
3
4
5
6
7
8
9
C:\Windows\system32>colour
Triplet: 16742297
Red: 255
Green: 119
Blue: 153
Dword: 1431655765
Bits: 064251800 6426180 34255400 6425180118 21191196118 2061798255 25525525485 8
58585
C:\Windows\system32>

The bits output strangely. Why is that?

What should have happened:
1
2
3
4
5
6
7
8
C:\Windows\system32>colour
Triplet: 16742297
Red: 255
Green: 119
Blue: 153
Dword: 1431655765
Bits: 0101 0101 0101 0101 0101 0101 0101 0101
C:\Windows\system32>

How can I correctly access all the bits of the variable in an array using a union?
Thanks!
For starters, you really should not use unions this way because the standard doesn't guarantee it will actually work. You should only ever access the last field you have written to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
union foo
{
  int a;
  short b;
};

foo f;

f.a = 5;
cout << f.a;  // OK, f.a was the last one written to
cout << f.b;  // BAD

f.b = 2;
cout << f.a;  // BAD
cout << f.b;  // OK 




Also, bools are not 1 bit wide, so an array of 8 of them will likely be larger than 1 byte.


There is no [blatantly easy] way to get individual bits of a value like this from a union. You could use bitfields, but that'd be a mess:

1
2
3
4
5
6
7
8
9
10
11
12
union
{
  unsigned long v;
  struct
  {
    unsigned bit0:1;
    unsigned bit1:1;
    unsigned bit2:1;
    unsigned bit3:1;
    //...
  };
};


But of course, whether or not bit0 is actually bit0 depends on several factors:
1) Whether your compiler decides to make unions work this way (most compilers do, but again it's not guaranteed)
2) The endianness of your system (little endian will have a different result from big endian).
The bits output strangely. Why is that?

You're incorrectly assuming that bool bits[32] take the same amount of space as unsigned long int value. bool is not implemented as a bit.
The representation of a bool is implementation defined, however, C++ guarantees the following:
1<=sizeof(bool)<=sizeof(long)
IOW, a bool must be at least one char in size and no larger than a long.
> They say that you can access the 4 bytes of a [unsigned] long int variable through a union.

yes, you can. The IS allows us to inspect the object representation of any object as an array of bytes. But only as an array of bytes (char or unsigned char).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <limits>
#include <bitset>

int main ()
{
    enum
    {
        NBITS_PER_BYTE = std::numeric_limits<unsigned char>::digits,
        NBYTES_LONG = sizeof(unsigned long),
        NBITS_LONG = NBITS_PER_BYTE * NBYTES_LONG
    } ;

    union
    {
        unsigned long integer ;
        unsigned char bytes[ NBYTES_LONG ] ;
    };

    integer = 0xFF7799  ;

    std::cout << "integer: " << std::hex << std::showbase << integer << '\n' ;

    std::cout << "bytes: " ;
    for( unsigned int v : bytes ) std::cout << v << ' ' ;

    std::cout << "\nbits: " ;
    for( auto c : bytes ) std::cout << std::bitset<NBITS_PER_BYTE>(c) << ' ' ;
    std::cout << '\n' ;
}


On my implementation:
integer: 0xff7799
bytes: 0x99 0x77 0xff 0
bits: 10011001 01110111 11111111 00000000




Well then, I've got to use these functions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool bitRead(unsigned long int val, unsigned char n){
  return val >> n & 1;
}
void bitBuffer(unsigned long int val, bool* buf, unsigned char n, unsigned char bitOrder){
  if (bitOrder == 0){ //LSBFIRST
    for(int i = 0; i < n; i++){
	  buf[i] = bitRead(val, i);
	}
  }
  else if (bitOrder == 1){ //MSBFIRST
    for(int i = n-1; i >= 0; i--){
	  buf[i] = bitRead(val, i);
	}
  }
}
If you need to deal with arbitrary arrays of bits, you might want to consider the bitset container.
http://www.cplusplus.com/reference/stl/bitset/
Topic archived. No new replies allowed.