Question

I just want to know about following structure declarations. Which one is better to use for memory allocation and why? And what about padding in case of unsigned char and unsigned int?

struct data{
 unsigned char a:3;
 unsigned char b:4;
}; 

and

struct data{
 unsigned int a:3;
 unsigned int b:4;
};
Was it helpful?

Solution

Bit fields should be declared with type signed int, unsigned int. Other types may or may not be supported.

From Atmel

in the C Standard, only “unsigned (int)” and “int” are acceptable datatypes for a bitfield member. Some compilers allow “unsigned char” .......

OTHER TIPS

On c99 standard (§6.7.2.1 #4)

A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.

If the actual type specifier used is int or a typedef-name defined as int, then it is implementation-defined whether the bit-field is signed or unsigned.

(§6.7.2.1 #15)

There may be unnamed padding at the end of a structure or union.

An implementation may allocate any addressable storage unit large enough to hold a bitfield.

Further (§6.7.2.1 #11)

A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field. As a special case, a bit-field structure member with a width of 0 indicates that no further bit-field is to be packed into the unit in which the previous bitfield,if any, was placed.

An unnamed bit-field structure member is useful for padding to conform to externally imposed layouts.

As Amogh (adamantly) and PHIfounder point out the only fully portable types are _Bool, signed int and unsigned int. A lot of compilers however allow other integral types to fiddle around with packing the bit-fields. Bit-fields in practice are often used to represent device registers, where typically each bit or set of bits has its own meaning. The packing of the bits is dictated by 6.7.2.1 ad 11 of the C standard

An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

Many compilers have adopted the convention that the 'addressable storage unit' is of the type specified in the source. The gcc compiler for example does not allow a 9-bit bit-field of type unsigned char, but it does allow it for an unsigned int type. In your examples the gcc compiler for the Pentium the struct using unsigned char will be 1 byte in size, whereas the one using unsigned int will be 4 bytes. Many compilers have also adopted the convention that if a bit-field does not fit, it will be not overlap with the next unit. This can however be enforced using a 0 width bit-field as dictated by 6.7.2.1 ad 12 of the standard

A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field. As a special case, a bit-field structure member with a width of 0 indicates that no further bit-field is to be packed into the unit in which the previous bit-field, if any, was placed.

If you mix bit-fields with non-bit-fields then 6.7.2.1 ad 15 dictates that the addressable units of the bit-fields and the non-bit-fields will have different addresses

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

Some architecture Application Binary Interfaces (ABI) of architectures enforce the implementation defined choices to ensure inter-operability of different compilers for that architecture.

which one is better to use, unsigned char or unsigned int and why?

unsigned int


The following is not portable and its consideration should be set aside.

// Only portable bit field types are _Bool, signed int, unsigned int
// This is not portable.
struct data{
  unsigned char a:3;
  unsigned char b:4;
};

That leaves OP alternative

struct data{
  unsigned int a:3;
  unsigned int b:4;
};

Which one is better to use for memory allocation and why?

If minimal memory is primary goal, do not use a bit field. Use the minimal integer type: unsigned char in this case. Add functions or defines to get and set.

void data_a_set(unsigned char *data, unsigned a) {
  *data = *data & ~7u | a & 7u;
}
unsigned data_a_get(unsigned char data) {
  return data & 7u;
}

// or for a more generic approach
#define B_BITS_PRIOR 3 /* sum of all previous bit widths */
#define B_BITS 4
#define MASK(w,p) (((1u << (w)) - 1) << (p))

void data_b_set(unsigned char *data, unsigned b) {
  *data &= ~MASK(B_BITS, B_BITS_PRIOR);
  *data |=  MASK(B_BITS, B_BITS_PRIOR) & (b << B_BITS_PRIOR);
}
unsigned data_b_get(unsigned char data) {
  return (data & MASK(B_BITS, B_BITS_PRIOR) >> B_BITS_PRIOR;
}

For types wider than unsigned, small changes needed to insure wider and and shift operations.

unsigned char could be wrapped in a struct if a unique type is needed.

struct data {
  unsigned char ab;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top