C Bit Fields
C language bit-field is a special struct member that allows us to define members by bits and specify the number of bits they occupy.
If the program's structure contains multiple switch variables, i.e., the variable value isTRUE/FALSE, as follows:
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;
This structure requires 8 bytes of memory space, but in reality we only store 0 or 1 in each variable.
In this case, C provides a way to better utilize memory space: when using such variables in a struct, you can define the width of the variable, telling the compiler that you will only use these bits.
For example, the above structure can be rewritten as:
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
Now, the status variable only occupies 4 bytes of memory space, but only 2 bits are used to store values.
If 32 variables with a width of 1 bit are used, the status struct still occupies only 4 bytes; but once 33 variables are used, the 33rd bit will be allocated to the next memory unit, and the entire struct starts occupying 8 bytes.
Let's look at the following example to understand this concept:
Example
#include <string.h>
/* Define a simple structure */
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/* Define a bit-field structure */
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( )
{
printf( "Memory size occupied by status1 : %zu\n", sizeof(status1));
printf( "Memory size occupied by status2 : %zu\n", sizeof(status2));
return 0;
}
When the above code is compiled and executed, it produces the following results:
Memory size occupied by status1 : 8 Memory size occupied by status2 : 4
The following table summarizes the characteristics and usage of bit-fields:
| Features | Description |
|---|---|
| Width specification | When defining a bit-field, you can specify the bit-field width of the member, i.e., the number of bits the member occupies. |
| Maximum width | The width of a bit-field cannot exceed the size of its data type, because the bit-field must fit the integer type used. |
| Data types | In standard C, it should beint、unsigned int、signed intinteger types, etc. Using other types (such as enums) depends on compiler implementation and is less portable. |
| Combination method | Bit-fields can be used alone, or can form a struct together with other ordinary members. |
| Access method | Through the dot operator (.) or the arrow operator for pointers (->) access, in the same way as ordinary struct members. |
Bit-field declaration
Some information does not need to occupy a full byte when stored; it only needs a few bits or one bit. For example, when storing a switch value, there are only two states, 0 and 1, so 1 bit is enough. To save storage space and simplify processing, C provides a data structure called "bit-field" or "bit segment."
The so-called "bit-field" divides the bits in a byte into several different regions and specifies the number of bits in each region. Each field has a field name, allowing operations to be performed by field name in the program. In this way, several different objects can be represented by the binary bit-fields of one byte.
A typical example: using 1 binary bit to store a switch value, which has only two states: 0 and 1.
Read external file formats — can read non-standard file formats, such as 9-bit integers.
Definition of bit fields and description of bit field variables
The definition of a bit-field is similar to a struct definition, and its form is:
struct 位域结构名
{
位域列表
};
The bit field list has the following form:
type [member_name] : width ;
The following is a description of the variable elements in a bit-field:
| element | Description |
|---|---|
| type | Can only be int (integer), unsigned int (unsigned integer), or signed int (signed integer), which determines how the value of the bit-field is interpreted. |
| member_name | The name of the bit-field. |
| width | The number of bits in the bit-field. The width must be less than or equal to the bit width of the specified type. |
Variables with a predefined width are calledBit Fields. Bit-fields can store numbers larger than 1 bit. For example, if you need a variable to store values from 0 to 7, you can define a bit-field with a width of 3 bits, as follows:
{
unsigned int age : 3;
} Age;
The above struct definition tells the C compiler that the age variable will use only 3 bits to store this value.
If the assigned value exceeds the range that 3 bits can represent, the excess part will beTruncation(see example 2 below).
int a:8;
int b:2;
int c:6;
}data;
The above code defines a variable namedstruct bsstruct, data is a structure variable of type bs, occupying a total of four bytes.
For bit-fields, their width cannot exceed the size of their data type; the size of int is usually 4 bytes (32 bits).
When adjacent bit-field fields have the same type, if the sum of their bit widths does not exceed the size of the type, the later field will be stored immediately next to the previous field, until it cannot fit.
Let's look at another example:
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
The above code defines a struct named packed_struct, which contains six member variables; pack is a struct variable of type packed_struct.
Here, packed_struct contains 6 members: four 1-bit identifiers f1..f4, a 4-bit type, and a 9-bit my_int.
Let's look at the following example:
Example 1
struct packed_struct {
unsigned int f1 : 1; // 1-bit bit-field
unsigned int f2 : 1; // 1-bit bit-field
unsigned int f3 : 1; // 1-bit bit-field
unsigned int f4 : 1; // 1-bit bit-field
unsigned int type : 4; // 4-bit bit-field
unsigned int my_int : 9; // 9-bit bit-field
};
int main() {
struct packed_struct pack;
pack.f1 = 1;
pack.f2 = 0;
pack.f3 = 1;
pack.f4 = 0;
pack.type = 7;
pack.my_int = 255;
printf("f1: %u\n", pack.f1);
printf("f2: %u\n", pack.f2);
printf("f3: %u\n", pack.f3);
printf("f4: %u\n", pack.f4);
printf("type: %u\n", pack.type);
printf("my_int: %u\n", pack.my_int);
return 0;
}
The above example defines a structure named packed_struct, which contains multiple bit field members.
In the main function, a struct variable pack of type packed_struct is created, and each bit-field member is assigned a value.
Then printf statements are used to output the value of each bit-field member.
The output is:
f1: 1 f2: 0 f3: 1 f4: 0 type: 7 my_int: 255
Example 2
#include <string.h>
struct
{
unsigned int age : 3;
} Age;
int main( )
{
Age.age = 4;
printf( "Sizeof( Age ) : %zu\n", sizeof(Age) );
printf( "Age.age : %d\n", Age.age );
Age.age = 7;
printf( "Age.age : %d\n", Age.age );
Age.age = 8; // Binary representation is 1000, which has four bits, exceeding the allowed range
printf( "Age.age : %d\n", Age.age );
return 0;
}
The above code will produce a truncation warning during compilation, and when executed, it produces the following results:
Sizeof( Age ) : 4 Age.age : 4 Age.age : 7 Age.age : 0
Calculate the number of bytes:
Example
struct example1 {
int a : 4;
int b : 5;
int c : 7;
};
int main() {
struct example1 ex1;
printf("Size of example1: %zu bytes\n", sizeof(ex1));
return 0;
}
In the above example, the example1 structure contains three bit field members a, b, and c, occupying 4 bits, 5 bits, and 7 bits respectively.
Use the sizeof operator to calculate the number of bytes of the example1 structure and output the result:
Size of example1: 4 bytes
Regarding the definition of bit fields, there are the following points to explain:
-
Bit-field members will try to be stored in the same storage unit. If the remaining space in that unit is not enough to hold the next bit-field, the bit-field will be stored starting from the next unit.
You can also intentionally make a bit-field start from the next unit. For example:
struct bs{ unsigned a:4; unsigned :4; /* 空域 */ unsigned b:4; /* 从下一单元开始存放 */ unsigned c:4; };In this bit-field definition, a occupies 4 bits of the first byte, the next 4 bits are filled with 0 to indicate unused, b starts from the second byte and occupies 4 bits, and c occupies 4 bits.
The width of a bit-field cannot exceed the length of the data type it depends on. Member variables all have types, and this type limits the maximum length of the member variable.:The following numbers cannot exceed this length.
-
A bit-field can be an unnamed bit-field, in which case it is only used for padding or adjusting position. Unnamed bit-fields cannot be used. For example:
struct k{ int a:1; int :2; /* 该 2 位不能使用 */ int b:3; int c:2; };
From the above analysis, it can be seen that a bit-field is essentially a struct type, except that its members are allocated by bits.
Use of bit fields
The use of bit-fields is the same as the use of struct members; its general form is:
bit-field variable name.bit-field name bit-field variable name->bit-field name
Bit fields allow output in various formats.
Please see the following example:
Example
int main(){
struct bs{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
bit.a=1; /* Assign a value to the bit field (note that the assignment must not exceed the allowed range of the bit field) */
bit.b=7; /* Assign a value to the bit field (note that the assignment must not exceed the allowed range of the bit field) */
bit.c=15; /* Assign a value to the bit field (note that the assignment must not exceed the allowed range of the bit field) */
printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* Output the contents of the three fields in integer format */
pbit=&bit; /* Assign the address of the bit-field variable bit to the pointer variable pbit */
pbit->a=0; /* Use a pointer to reassign the bit-field a to 0 */
pbit->b&=3; /* Uses the compound bitwise operator "&=", equivalent to: pbit->b=pbit->b&3. The original value of bit-field b is 7, and the bitwise AND with 3 gives 3 (111&011=011, decimal value 3) */
pbit->c|=1; /* Uses the compound bitwise operator "|=", equivalent to: pbit->c=pbit->c|1, and the result is 15 */
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* Output the values of these three fields using pointers */
return 0;
}
When the above code is compiled and executed, it produces the following results:
1,7,15 0,3,15
In the above example program, a bit-field struct bs is defined, with three bit-fields a, b, c, as well as a variable bit of type bs and a pointer variable pbit pointing to type bs.
This shows that bit-fields can also use pointers.
other extensions