tags:

views:

116

answers:

2

let us consider following code

#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct bf_{
    unsigned x:4;
    unsigned y:4;
    unsigned z:4;
    unsigned  w:4;
    }bf;
int main(){
    unsigned short i=8;
    unsigned short j=9;
    bf* bitfields=(bf *)&i;
    bf*bit=(bf*)&j;
    bitfields->w=12;
    printf("%d\n",bitfields->x);
    printf("%d\n",bit->y);
    printf("%d\n",bitfields->w);



     return 0;
}

this fragment

unsigned short j=9;
bf*bit=(bf*)&j;
printf("%d\n",bit->y);

i have add after guess some interesting characteristic of this code for example after this place

bf* bitfields=(bf *)&i;

when we write printf("%d\n",bitfields->x); which prints 8 i understand that using pointers and references value of i will be granted to x and so it prints 8 for instance when we write bitfiled->y it writes 0 so i decided to introduce second element variable j create new instance of bf structer and make reference of j after which statement bit->y should write 9 because as i understand it is order definition but it gives me 0 why? please explain me how this code works?i am not english speaker so please sorry for my bad english

+3  A: 

First of all, there are no references used in this code. The & character, when used as a unary operator (instead of as part of a type name), as in this context, means "address-of". So &i is "the address of i", not "a reference to i".

I'm not sure where you're getting the idea that using the value 9 as your bf struct should cause y to get the value 9. When you write this:

bf* bitfields=(bf *)&i;

What happens is that you are telling the compiler "treat the value at memory location &i as if it were a bf structure". The bf structure is defined so that, starting from the least significant (right-most) bits, the first four bits are the x value, the second four bits are the y value, the third four bits are the z value, etc.

So since the value at the location &i is 8, and 8 in 16-bit binary is

0000 0000 0000 1000 

The fields of bitfields are going to be:

0000 0000 0000 1000 
  w    z    y    x

So the value of x (a 4-bit unsigned integer) is 8, while the values of y, z, and w are 0.

In the case where you write

bf*bit=(bf*)&j;

you are doing the same thing as above, except now the value is 9, so the assignments are:

0000 0000 0000 1001 
  w    z    y    x

So x has the value 9, and the other values are still 0.

If you want to assign the value 9 to y instead of x, the assignments would need to look like this:

0000 0000 1001 0000 
  w    z    y    x

So the value you would have to use is the value with the 16-bit binary representation

0000 0000 1001 0000 

Which is 144. So if you let j = 144 instead of j = 9, you would observe that bit->y is 9, and all of the other fields in bit are 0.

Tyler McHenry
Is the order of `x y z w` reversed because of how the struct is stored in memory or because of how the short is stored?
Kyle
@Kyle Technically, the whole thing is implementation-defined. I've inferred from his example that the `x` field is being assigned to the least-significant 4-bits, so I'm assuming that the compiler has chosen to lay out the bitfields in order of least-significant to most-significant bits. They appear "reversed" in my figures because in English, numbers are written in the opposite order, with the most-significant digits first.
Tyler McHenry
Cool, it just has to do with the endianness then.
Kyle
0x0090 != 72. 9 * 16 = 144. But the C++ language makes few guarantees about the layout of bitfields.
Ben Voigt
@Ben right you are. I had simply been lazy and typed "0b1001000 in decimal" into Google, and you'll note that I missed a 0.
Tyler McHenry
A: 

I think it's because of the packing that occurs when the struct or class is compiled. See these links:

http://msdn.microsoft.com/en-us/library/83ythb65.aspx#vclrfhowalignworkswithdatapacking.
http://msdn.microsoft.com/en-us/library/2e70t5y1%28VS.80%29.aspx

By default, the size of a struct at compile time, is not the same as the total size of it's members.

Mark Ingram
Bitfields generally get packed in this scenario. On most implementations, the compiler will refuse to let a bitfield cross an alignment boundary determined by the underlying type (which here is `unsigned int`), but that wouldn't come into play here.
Ben Voigt