Clarification of the semantics of bit field ordering in C

I'm having problems understanding the exact meaning of the paragraph of the standard of the C99 (N1256) project about bit fields (6.7.2.1:10):

6.7.2.1 Structure and Association Specifications

[...]

Semantics

[...]

An implementation can allocate any addressable storage block large enough to hold a bitfield. If there is enough space left, a bit field that immediately follows another bit field in the structure should be packed into adjacent bits of the same block. If there is not enough space, then whether a bit field that does not fit will fit in the next block or overlap adjacent units is determined by the implementation. The order of distribution of bit fields within the device (from high order to low or low order) is determined by the implementation. Alignment of the storage address block is unspecified.

The underlined sentence extends my English skills to the limit: I don’t understand whether this applies to individual bit fields within a unit or to bits ordering within individual bit fields or something else.

I will try to make my question more clear with an example. Suppose unsigned ints are 16 bits, that the implementation selects unsigned int as the storage address block (and these bytes are 8 bits wide), and no other alignment or padding problems arise:

struct Foo { unsigned int x : 8; unsigned int y : 8; }; 

so if the fields x and y are stored inside the same block, what is defined by the implementation in accordance with this sentence? As I understand it, this means that inside this unsigned int unit x can be stored either at a lower address than at y , or vice versa, but I'm not sure, since intuitively I think that if there are no bit fields overlap with the two basic storage units , the declaration order will impose the same order for the base bit fields.

Note I am afraid that there is no terminological subtlety (or, worse, technical), but I could not understand what exactly.

Any pointer appreciated. Thanks!

+4
source share
3 answers

I do not see what is unclear with

The order of distribution of bit fields within a unit (from high order to low or low order) is determined by the implementation.

It talks about the distribution of a bit field, not about the bits inside the field. So, in addition to elements other than the bit field, you cannot be sure in what order the bit fields are ordered inside the address device.

Otherwise, it is guaranteed that the representation of the bit field itself will be β€œthe same” as the base type, divided by value bits and a signed bit (if applicable).

In essence, this suggests that the anatomy of a storage unit that contains bit fields is a specific implementation, and you should not try to access the bits through other means ( union or so), as this will make your code intolerable.

+6
source

I take it upon myself, the C99 specification talks about the bit sign of bit fields and how they are arranged in a β€œunit” (byte word, etc.). In fact, you are on your own if you start creating structures.

Example

 bit ex1 ex2 ex3 D7 x3 y0 x0 D6 x2 y1 x1 D5 x1 y2 x2 D4 x0 y3 x3 D3 y3 x0 y0 D2 y2 x1 y1 D1 y1 x2 y2 D0 y0 x3 y3 

Above are three different schemes for arranging two 4-bit fields in a byte block. All are legal with respect to C99.

+1
source

Gibbon1's answer is correct, but I think the sample code is useful for this kind of questions.

 #include <stdio.h> int main(void) { union { unsigned int x; struct { unsigned int a : 1; unsigned int b : 10; unsigned int c : 20; unsigned int d : 1; } bits; } u; ux = 0x00000000; u.bits.a = 1; printf("After changing a: 0x%08x\n", ux); ux = 0x00000000; u.bits.b = 1; printf("After changing b: 0x%08x\n", ux); ux = 0x00000000; u.bits.c = 1; printf("After changing c: 0x%08x\n", ux); ux = 0x00000000; u.bits.d = 1; printf("After changing d: 0x%08x\n", ux); return 0; } 

On a small x86-64 processor using MinGW GCC, the output is:

After changing a: 0x00000001

After changing b: 0x00000002

After changing c: 0x00000800

After changing d: 0x80000000

Since this is a union, unsigned int (x) and bitfield structure (a / b / c / d) occupy the same storage block. The distribution order of the [bit] bit determines whether u.bits.a is the least significant bit x or the most significant bit x. Typically, on a small-end machine:

 u.bits.a == (ux & 0x00000001) u.bits.b == (ux & 0x000007fe) >> 1 u.bits.c == (ux & 0xeffff800) >> 11 u.bits.d == (ux & 0x80000000) >> 31 

and on a big end machine:

 u.bits.a == (ux & 0x80000000) >> 31 u.bits.b == (ux & 0x7fe00000) >> 21 u.bits.c == (ux & 0x001ffffe) >> 1 u.bits.d == (ux & 0x00000001) 

What the standard says is that the C programming language does not require any particular endianness. Hospital and low-end machines can put data in the order most natural for their addressing scheme.

+1
source

Source: https://habr.com/ru/post/1500873/


All Articles