C++ Logo

std-discussion

Advanced search

Proposal: Small bit fields, and their access requirements

From: <John.Adriaan_at_[hidden]>
Date: Fri, 10 Jan 2020 01:02:23 +1100
Bit fields in C/C++ code are mostly used to map existing hardware registers
and the field positions within them [citation needed].

 

For the following example hypothetical device, please assume the following:

I. char is 8 bits;
II. sizeof(bool)==1;
III. sizeof(unsigned)==4;
IV. An "LSb" interpretation for bit fields (yes, I know bit order is
compiler-sensitive).

 

    typedef unsigned B;

    typedef unsigned U;

    struct S {

        bool f1 : 1; // Explicitly bool

        B f2 : 1; // I'll be changing B, once, later

    // U : 7; // Line "Optional 7" - designed to change the size
of S to >8 bits

    // U : 15; // Line "Optional 15" - designed to change the size
of S to >16 bits
    // U : 0; // Line "Optional 0" - the ultimate purpose of this
proposal

    }; // S

    

    /* Insert whatever linker-specific magic is required to get this to a
particular address. */

    volatile S s;

 

Two major compilers have been used to guide this submission: clang and gcc.
Both have been targeted at both ARM and x86-64. Both do what is described
below for both.

Note that gcc has the flag `-fstrict-volatile-bitfields` set, to enforce
access to the "underlying type" (Note that a request to determine exactly
what that means has been submitted.)

 

A. Given the above definitions, accesses to :

a. f1 are 8-bit oriented;
b. f2 are 8-bit oriented.

B. If I change the definition of B to "typedef bool B;" (for ONLY this
scenario), accesses to :

a. f1 are 8-bit oriented;
b. f2 are 8-bit oriented.

C. If I un-comment (ONLY) the "Optional 7" line, then accesses to :

a. f1 are 8-bit oriented;
b. f2 are 16-bit oriented.

D. If I un-comment (ONLY) the "Optional 15" line, then accesses to :

a. f1 are 8-bit oriented;
b. f2 are 32-bit oriented.

E. In each of the above examples, if I ALSO un-comment the "Optional 0"
line, then accesses in each case don't change.

 

ASIDE: To me, the above examples highlight a deficiency with the standard,
such that defining surrounding bit fields shouldn't be permitted to
determine the access requirements of the current bit field. In my opinion,
the standard should explicitly enforce the compiler to access the
"underlying type" of the field, suitably aligned to the requirements of the
location - but I understand that this is not a good idea, considering that
existing code indiscriminately uses "int" for bit fields.

 

I propose a change to the wording in the standard. To paraphrase, the
presence of a ": 0" bitfield suggests "align the NEXT field with the next
alignment boundary". I propose that this should read "pad the CURRENT struct
to the next alignment boundary for this CURRENT field's type".

 

ASIDE: Note the repetition of "CURRENT" - to my reading, the existing
standard potentially leaves undetermined whether the alignment should be the
responsibility of the current padding field or the new field.

 

This has two advantages:

 

1. In all of the above cases, enlarging the size of S past f1 and f2 to
32 bits or more causes the compilers to access f2 "correctly". That is, as
long as the fundamental size of S is large enough to accommodate a 32-bit
access, the compiler will do so;
2. In all cases where ": 0" is used BETWEEN bit fields, the effect of
the wording change is nil. The only scenario where this has ANY effect is
when the ": 0" definition is last in the struct - and in that case, isn't
that probably what the developer wanted anyway?


Received on 2020-01-09 08:04:57