views:

199

answers:

3

To begin with, the application in question is always going to be on the same processor, and the compiler is always gcc, so I'm not concerned about bitfields not being portable.

gcc lays out bitfields such that the first listed field corresponds to least significant bit of a byte. So the following structure, with a=0, b=1, c=1, d=1, you get a byte of value e0.

struct Bits {
  unsigned int a:5;
  unsigned int b:1;
  unsigned int c:1;
  unsigned int d:1;
} __attribute__((__packed__));

(Actually, this is C++, so I'm talking about g++.)

Now let's say I'd like a to be a six bit integer.

Now, I can see why this won't work, but I coded the following structure:

struct Bits2 {
  unsigned int a:6;
  unsigned int b:1;
  unsigned int c:1;
  unsigned int d:1;
} __attribute__((__packed__));

Setting b, c, and d to 1, and a to 0 results in the following two bytes:

c0 01

This isn't what I wanted. I was hoping to see this:

e0 00

Is there any way to specify a structure that has three bits in the most significant bits of the first byte and six bits spanning the five least significant bits of the first byte and the most significant bit of the second?

Please be aware that I have no control over where these bits are supposed to be laid out: it's a layout of bits that are defined by someone else's interface.

+3  A: 

Usually you can't do strong assumptions on how the union will be packed, every compiler implementation may choose to pack it differently (to save space or align bitfields inside bytes).

I would suggest you to just work out with masking and bitwise operators..

from this link:

The main use of bitfields is either to allow tight packing of data or to be able to specify the fields within some externally produced data files. C gives no guarantee of the ordering of fields within machine words, so if you do use them for the latter reason, you program will not only be non-portable, it will be compiler-dependent too. The Standard says that fields are packed into ‘storage units’, which are typically machine words. The packing order, and whether or not a bitfield may cross a storage unit boundary, are implementation defined. To force alignment to a storage unit boundary, a zero width field is used before the one that you want to have aligned.

Jack
+1  A: 

C/C++ has no means of specifying the bit by bit memory layout of structs, so you will need to do manual bit shifting and masking on 8 or 16bit (unsigned) integers (uint8_t, uint16_t from <stdint.h> or <cstdint>).

Of the good dozen of programming languages I know, only very few allow you to specify bit-by-bit memory layout for bit fields: Ada, Erlang, VHDL.

(Community wiki if you want to add more languages to that list.)

ndim
+3  A: 

(Note that all of this is gcc-specific commentary - I'm well aware that the layout of bitfields is implementation-defined).

Not on a little-endian machine: The problem is that on a little-endian machine, the most significant bit of the second byte isn't considered "adjacent" to the least significant bits of the first byte.

You can, however, combine the bitfields with the ntohs() function:

union u_Bits2{
    struct Bits2 {
      uint16_t _padding:7;
      uint16_t a:6;
      uint16_t b:1;
      uint16_t c:1;
      uint16_t d:1;
    } bits __attribute__((__packed__));
    uint16_t word;
}

union u_Bits2 flags;
flags.word = ntohs(flag_bytes_from_network);

However, I strongly recommend you avoid bitfields and instead use shifting and masks.

caf
I suppose you meant "Note on a little-endian", not "Not on a little-endian". I think I understand what you're saying, though. On a little-endian machine, the adjacency of bits is determined by how bits are packed into a machine word, and the compiler assumes that machine words are going to be byte-swapped.I'm going to take others' advice and do masking and shifting, but thanks for figuring out what's going on here.
Jim Hunziker
Yes - gcc packs the bitfields within the *word* from lowest bit to highest bit - and on a little endian machine, the lowest 8 bits are stored in the first byte.
caf