C language learning notes - bit field

Keywords: C Single-Chip Microcomputer

    in C language, Boolean bool variables are often used when operating data with only true and false states. If multiple states need to be observed at the same time, the operation efficiency of selection bits will be higher. 8 bits of a byte are used to represent 8 states respectively. It saves memory and is more efficient to process. However, this method has a disadvantage, which is not intuitive. For example, 0x5C has to convert the state of each bit to know. At the same time, when operating a single bit, it must also use bit operation operations, such as bit and, bit or, XOR.

  if you are familiar with MCU, you will think of whether you can directly operate a single bit of a byte in C language like operating register?

  for example, this is the port direction configuration register of a single chip microcomputer. Each port has 8 ports, and each port can be configured as output mode or input mode separately. For example, set PA now_ DDR.DDR3 = 1; PA_ DDR.DDR6 = 0; Then it means that port 3 of PA port is set as output mode and port 6 is set as input mode. When operating in this way, it looks more intuitive than using bit operation directly.

   there is also an operation mode in C language. It is called bit field. Bit field is a group of adjacent bits in a signed int or unsigned int variable. Fields are created by a structure declaration that provides a label for each field and determines the width of the field.

struct
{
    unsigned int Sun: 1;
    unsigned int Mon: 1;
    unsigned int Tue: 1;
    unsigned int Wed: 1;
    unsigned int Thur: 1;
    unsigned int Fri: 1;
    unsigned int Sat: 1;
} week;

  in the above week structure, seven 1-bit fields are provided, and each field represents one day. This allows you to assign a value to each character through the structure member operator dot (.).

		week.Mon = 1;
        week.Tue = 1;
        week.Wed = 1;
        week.Thur = 1;
        week.Fri = 1;
        week.Sat = 0;
        week.Sun = 0;

   set the value from Monday to Friday to 1 and the value of weekend to 0 through the structure operator. In this way, a bit in the byte can be operated alone, which is very similar to the operation of the register in the single chip microcomputer. Since each field occupies only one bit, the value of the character can only be 0 or 1. You can also set each field to multiple bits.

struct {
    unsigned int code1 : 2;
    unsigned int code2 : 3;
    unsigned int code3 : 8;
} prcode;

   a 2-bit field, a 3-bit field and an 8-bit field are created. It can be assigned as follows:

prcode.code1 = 3;
prcode.code2 = 7;
prcode.code3 =  255;

   the size of the assignment cannot exceed the maximum range that the field can represent.

   in the first example, all the bits of the field add up to only 7 bits, but in the second example, all the bits of the field add up to 13 bits. How are these two cases stored in memory?

   in C language, if the total number of bits declared exceeds the size of an unsigned int type, the storage location of the next unsigned int type will be used. A field is not allowed to cross the boundary between two unsigned ints, and the compiler will automatically move the cross-border word segments. Keep the boundaries of unsigned ints aligned.

  in order to observe the data in the memory conveniently, the code is transplanted to the single chip microcomputer. To observe the storage in memory.

struct
{
    unsigned int Sun: 1;
    unsigned int Mon: 1;
    unsigned int Tue: 1;
    unsigned int Wed: 1;
    unsigned int Thur: 1;
    unsigned int Fri: 1;
    unsigned int Sat: 1;
} week;

struct
{
    unsigned int code1 : 5;
    unsigned int code2 : 5;
    unsigned int code3 : 7;
} prcode;

		week.Sun = 1;
		week.Mon = 0;
        week.Tue = 1;
        week.Wed = 0;
        week.Thur = 1;
        week.Fri = 0;
        week.Sat = 1;
       
      
        prcode.code1 = 0x03;
        prcode.code2 = 0x11;
        prcode.code3 =  0x22;

        cnt1 = sizeof(week);
        cnt2 = sizeof(prcode);

   assign values to each segment of the two bit fields respectively, and finally calculate the memory occupied by the two bit fields through sizeof().

   week after the assignment of each field is completed, the data in memory becomes 55.

  field Sun is the lowest bit and field Sat is the highest bit.
  next, store the data of the prcode field.

   when 0x03 and 0x11 are stored, the data in the memory becomes 02.23

   code1 field and code1 field account for 5 bits respectively, so the lowest 5 bits are the value of code1, followed by the value of code2. The remaining bits are 0 by default.


   finally, assign a value to code3 field. code3 occupies 7 bits and the value is 0x22.

   finally, it is calculated that week occupies 2 bytes and prcode occupies 4 bytes.

  when the compiler automatically aligns the boundary in memory, an unnamed "hole" will be left. You can fill the unnamed "hole" with the unnamed field width. The following code:

struct
{
    unsigned int code1 : 1;
    unsigned int       : 4;
    unsigned int code2 : 1;
    unsigned int       : 1;
    unsigned int code3 : 1;
} prcode;

  there are four holes between code1 and code2 and one hole between code2 and code3.

  the data in memory is a1.

  you can see that the position of "hole" is automatically filled with 0. In C language, the bit field takes unsigned int as the basic layout unit. Even if the member of a structure is a 1-bit field, the size of the structure in memory is also an unsigned int type size. In addition, boolean type (bool) in bit field can also be used.

Posted by a.beam.reach on Wed, 10 Nov 2021 10:52:26 -0800