Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do bit fields interplay with bits padding in C++

See the C version of this questions here.

I have two questions concerning bit fields when there are padding bits.

Say I have a struct defined as

struct T { 
    unsigned int x: 1; 
    unsigned int y: 1;
};

Struct T only has two bits actually used.

Question 1: are these two bits always the least significant bits of the underlying unsigned int? Or it is platform dependent?

Question 2: Are those unused 30 bits always initialized to 0? What does the C++ standard say about it?

like image 851
John Z. Li Avatar asked May 20 '19 08:05

John Z. Li


People also ask

How do bit fields work in C?

In C, we can specify size (in bits) of structure and union members. The idea is to use memory efficiently when we know that the value of a field or group of fields will never exceed a limit or is within a small range. For example, consider the following declaration of date without the use of bit fields.

How are bit fields stored in memory C?

Again, storage of bit fields in memory is done with a byte-by-byte, rather than bit-by-bit, transfer.

How do bit fields work?

In programming terminology, a bit field is a data structure that allows the programmer to allocate memory to structures and unions in bits in order to utilize computer memory in an efficient manner. Since structures and unions are user-defined data types in C, the user has an idea of how much memory will they occupy.

Can we use bit array and bit field interchangeable?

No, you can't. Bit field can only be used with integral type variables.

How to understand bit fields in C?

In order to understand bit fields, we need to have a clear understanding of Structures and Unions in C. In programming terminology, a bit field is a data structure that allows the programmer to allocate memory to structures and unions in bits in order to utilize computer memory in an efficient manner.

How many padding bits are there between the bit-fields?

This is achieved by padding bits between the bit-fields. The size of structure 'A' is 1 byte. In structure B, the first unnamed bit-field skips 2 bits; the zero width bit-field after c2 causes c3 to start from the char boundary (so 3 bits are skipped between c2 and c3. There are 3 padding bits after c4.

How to declare a bit-field inside a structure?

The declaration of a bit-field has the following form inside a structure − The following table describes the variable elements of a bit field − An integer type that determines how a bit-field's value is interpreted. The type may be int, signed int, or unsigned int. The name of the bit-field. The number of bits in the bit-field.

Why do we add padding after the first byte in C?

In our example, adding padding after the first byte, the char would ensure that the last part of the data would be properly aligned in memory. See the below example. ( * is padding). Now, the processor or controller will directly read the 0x00000004 in one memory cycle and no bit shifting is required. We will check this with the below example.


Video Answer


2 Answers

Question 1: are these two bits always the least significant bits of the underlying unsigned int? Or it is platform dependent?

Very platform dependent. The standard even has a note just to clarify how much:

[class.bit]

1 ...Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [ Note: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others.  — end note ]

You can't assume much of anything about the object layout of a bit field.

Question 2: Are those unused 30 bits always initialized to 0? What does the C++ standard say about it?

Your example has a simple aggregate, so we can enumerate the possible initializations. Specifying no initializer...

T t;

... will default initialize it, leaving the members with indeterminate value. On the other hand, if you specify empty braces...

T t{};

... the object will be aggregate initialized, and so the bit fields will be initialized with {} themselves, and set to zero. But that applies only to the members of the aggregate, which are the bit fields. It's not specified what value, if any, the padding bits take. So we cannot assume they will be initialized to zero.

like image 176
StoryTeller - Unslander Monica Avatar answered Sep 23 '22 16:09

StoryTeller - Unslander Monica


Q1: Usually from low to hi (i.e. x is 1 << 0, y is 1 << 1, etc).

Q2: The value of the unused bits is undefined. On some compilers/platforms, stack initialised variables might be set to zero first (might!!), but don't count on it!! Heap allocated variables could be anything, so it's best to assume the bits are garbage. Using a slightly non standard anonymous struct buried in a union, you could do something like this to ensure the value of the bits:

union T {
 unsigned intval;
 struct { 
   unsigned x : 1;
   unsigned y : 1;
 };
}; 

T foo;
foo.intval = 0;
like image 35
robthebloke Avatar answered Sep 23 '22 16:09

robthebloke