Bit field's memory management in C

bit fields in c examples
c bit field union
advantages of bit field in c
how bit fields are stored in memory
c bit field initialization
bit field in c pdf
bit fields in c programming
c bit field array

To understand the bit field memory storage, I have created the test program below.

#include <stdio.h>

int main()
{
    int a;
    typedef struct {
        int b7 : 1;
        int b6 : 1;
        int b5 : 1;
        int b4 : 1;
        int b3 : 1;
        int b2 : 1;
        int b1 : 1;
        int b0 : 1;
    } byte;

    byte ab0 = {0,0,0,0,0,0,0,1};
    a = *(int*)&ab0;
    printf("ab0 is %x \n",a);

    byte ab1 = {0,0,0,0,0,0,1,0};
    a = *(int*)&ab1;
    printf("ab1 is %x \n",a);

    byte ab2 = {0,0,0,0,0,1,0,0};
    a = *(int*)&ab2;
    printf("ab2 is %x \n",a);

    byte ab3 = {0,0,0,0,1,0,0,0};
    a = *(int*)&ab3;
    printf("ab3 is %x \n",a);

    byte ab4 = {0,0,0,1,0,0,0,0};
    a = *(int*)&ab4;
    printf("ab4 is %x \n",a);

    byte ab5 = {0,0,1,0,0,0,0,0};
    a = *(int*)&ab5;
    printf("ab5 is %x \n",a);

    byte ab6 = {0,1,0,0,0,0,0,0};
    a = *(int*)&ab6;
    printf("ab6 is %x \n",a);

    byte ab7 = {1,0,0,0,0,0,0,0};
    a = *(int*)&ab7;
    printf("ab7 is %x \n",a);

    return 0;
}

Compile and run

gcc -Wall test.c
./a.out 
ab0 is 80 
ab1 is 40 
ab2 is 20 
ab3 is 10 
ab4 is 8 
ab5 is 4 
ab6 is 2 
ab7 is 1 

Same output when I run code online http://codepad.org/ntqyuixp

I am not able to understand its output.

Expected Output: As per my understanding output should be like

ab0 is 1 
ab1 is 2 
ab2 is 4 
ab3 is 8 
ab4 is 10 
ab5 is 20 
ab6 is 40 
ab7 is 80
  • Please let me know what I am missing.

  • Does endianness play any role?

  • How should the code be written for my expected behaviour?

The order of the bits in a bit-field is implementation defined. The implementation has a different definition from the one you expected — and that's almost all there is to say about it.

Almost everything about bit-fields is implementation defined.

ISO/IEC 9899:2011 §6.7.2.1 Structure and union specifiers

¶4 The expression that specifies the width of a bit-field shall be an integer constant expression with a nonnegative value that does not exceed the width of an object of the type that would be specified were the colon and expression omitted.122) If the value is zero, the declaration shall have no declarator.

¶5 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. It is implementation-defined whether atomic types are permitted.

¶9 A member of a structure or union may have any complete object type other than a variably modified type.123) In addition, a member may be declared to consist of a specified number of bits (including a sign bit, if any). Such a member is called a bit-field;124) its width is preceded by a colon.

¶10 A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits.125) If the value 0 or 1 is stored into a nonzero-width bit-field of type _Bool, the value of the bit-field shall compare equal to the value stored; a _Bool bit-field has the semantics of a _Bool.

¶11 An implementation may allocate any addressable storage unit large enough to hold a bitfield. 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.

¶12 A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field.126) 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.

122) While the number of bits in a _Bool object is at least CHAR_BIT, the width (number of sign and value bits) of a _Bool may be just 1 bit.

123) A structure or union cannot contain a member with a variably modified type because member names are not ordinary identifiers as defined in 6.2.3.

124) The unary & (address-of) operator cannot be applied to a bit-field object; thus, there are no pointers to or arrays of bit-field objects.

125) As specified in 6.7.2 above, 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.

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

Note ¶11 in particular:

The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.

Note, too, that 'implementation-defined' means that the implementation must define what it does. That is, you can inspect documentation and the documentation must tell you what the compiler does (if the compiler is standard-compliant). This is different from 'unspecified' and some of the other terms you'll encounter — a compiler-writer would almost certainly not change the behaviour of bit-fields casually from release to release. In contrast, the way that arguments to functions are evaluated, for example, could change from release to release, or according to optimization options chosen at compile time, etc.

§6.5.2.2 Function calls

There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.94)

94) In other words, function executions do not ‘‘interleave’’ with each other.

6.7.2 Type specifiers

5 Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int.

Bit field, C - Bit Fields - Suppose your C program contains a number of TRUE/FALSE variables grouped in a structure called status, as follows − The variables defined with a predefined width are called bit fields. A bit field can hold more than a single bit; for example, if you need a variable to store a value from 0 to 7, then you can define a bit field with a width of 3 bits as follows − struct { unsigned int age : 3; } Age;

bit fields are non portable and machine dependent.

Limitations of using bit fields

When using bit fields, be aware of the following issues:

  1. The code will be non-portable since the organization of bits-within-bytes and bytes-within-words is machine dependent.
  2. You cannot take the address of a bit field; so the expression &mystruct.x is illegal if x is a bit field identifier, because there is no guarantee that mystruct.x lies at a byte address.
  3. Bit fields are used to pack more variables into a smaller data space, but causes the compiler to generate additional code to manipulate these variables. This costs in terms of code size and execution time.

C - Bit Fields, Bit Fields 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  the name of the bit field that is being declared. The name is optional: nameless bitfields introduce the specified number of bits of padding size - an integral constant expression with a value greater or equal to zero. When greater than zero, this is the number of bits that this bit field will occupy.

For linux on x86 the relevant ABI document can be found here(pdf).

Specifically related to bitfields:

‘‘Plain’’ bit-fields (that is, those neither signed nor unsigned) always have nonnegative values. Although they may have type char, short, int, or long (which can have negative values), these bit-fields have the same range as a bit-field of the same size with the corresponding unsigned type.

Bit-fields obey the same size and alignment rules as other structure and union members, with the following additions:

Bit-fields are allocated from right to left (least to most significant). A bit-field must entirely reside in a storage unit appropriate for its declared type. Thus a bit-field never crosses its unit boundary.

Bit-fields may share a storage unit with other struct / union members, including members that are not bit-fields. Of course, struct members occupy different parts of the storage unit. Unnamed bit-fields’ types do not affect the alignment of a structure or union, although individual bit-fields’ member offsets obey the alignment constraints.

The

Bit Fields in C, The constant-expression specifies the number of bits the member occupies in the structure. Anonymous bit fields — that is, bit-field members with  Bit Fields 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 withing a small range.

C++ Bit Fields, In addition to declarators for members of a structure or union, a structure declarator can also be a specified number of bits, called a "bit field. the name of the bit field that is being declared. The name is optional: nameless bit fields introduce the specified number of bits of padding width - an integer constant expression with a value greater or equal to zero and less or equal the number of bits in the underlying type.

C Bit Fields, Now I am curious, [are flags] the only way bit-fields are used practically? No, flags are not the the only way bit-fields are used. They can also be  Bit fields have the same semantics as the integer type. This means a bit field is used in expressions in exactly the same way as a variable of the same base type would be used, regardless of how many bits are in the bit field.

When to use bit-fields in C?, struct abc { unsigned int a : 1; unsigned int b : 1; };. Now, the above structure will require 4 bytes of memory space for status variable but only 2 bits will be used to​  The underlying type of a bit field must be an integral type, as described in Built-in types. If the initializer for a reference of type const T& is an lvalue that refers to a bit field of type T, the reference is not bound to the bit field directly. Instead, the reference is bound to a temporary initialized to hold the value of the bit field.

Comments
  • I know that you only do this for the experiment, but your method of casting to int* and then derefferencing is erroneous and will lead you to a lot of trouble if you would apply this in production code. Don't do this. The method that is foreseen by the standard to do inspections like this are union.
  • you mean it will vary on compiler to compiler ? and i should not depend on this?
  • @JonathanLeffler: i would think bit field memory management varies from machine to machine and not with compiler to compiler. same compiler on different machine may behave differently but not the otherwise.
  • You need to look at whether the ABI (application binary interface) for the machine (hardware and operating system combination) mandates the bit-field layout. If it does, there is a high probability that the compilers all conform to the ABI. If the ABI is silent, different compilers may do as they please; the C standard says they can and the ABI does not overrule it. You still have to read the compiler documentation to know whether it adheres to the ABI (and what it does, whichever standard it follows).
  • GCC docs state that the order of allocation of bit-fields within a unit [is] determined by ABI [4.9 Structures, unions, enumerations, and bit-fields], and the ELF x86_64 psABI states that bit-fields are allocated from right to left. [3.1.2 Data Representation]
  • @ninjalj: thanks — that's useful information. It's sorely tempting to trot out the jibe "that's the wonderful thing about standards; there are so many to choose from". It can be hard to know which standard is influencing each decision by a compiler.
  • 1. The code will be portable, as long as it is internal data structures, and you don't make an extra effort to check the order of the bits.
  • bit fields are a standard C tool so, as long as you use what the standard provides, your code will be portable.