[C Advanced] Custom Type (2) Bit Segment - Enumeration - Union

content

1. Bit segment

      1.1, what is a bit segment

      1.2. Memory allocation of bit segment

      1.3. Cross-platform problems of bit segment

      1.4, the application of bit segment

2. Enumeration

      2.1, the definition of enumeration type

      2.2, the advantages of enumeration

      2.3, the use of enumeration

3. Union

      3.1. Definition of union types

      3.2, the characteristics of the joint

      3.3. Calculation of joint size


1. Bit segment

1.1, what is a bit segment

  • The declaration and structure of bit fields are similar, with two differences:
  1. The members of the bit field must be int, unsigned int, or signed int.
  2. The member name of the bit field is followed by a colon and a number.
  • for example:
#include<stdio.h>
struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n", sizeof(struct A)); //8
	return 0;
}
  • A is a bit segment type. What is the size of that segment A?
  • Parse:

In the above code, _a : 2 means _a only needs 2 bits, _b : 5 means _b only needs 5 bits, _c : 10 means _c only needs 10 bits, _d : 30 means _d only needs 10 bits 30 bits are required. Adding all these bits together makes a total of 47 bits, so how come there are 8 bytes? Need to understand the following bit segment memory allocation:

1.2. Memory allocation of bit segment

  1. The members of the bit field can be of type int unsigned int signed int or char (belonging to the integer family)
  2. The space of the bit field is opened up by 4 bytes ( int ) or 1 byte ( char ) as needed.
  3. Bit fields involve many uncertain factors. Bit fields are not cross-platform. Programs that focus on portability should avoid using bit fields.
  • In summary:

_a is of int type. First open 4 bytes, _a occupies 2 bits, and 30 bits are left, _b occupies 5 bits, and 25 bits are left, _c occupies 10 bits, and 15 bits are left, and the size of 15 bits is not enough _d The size of _d is 30bit, and _d is still of type int, so 4 bytes are opened again, and the size of _d is loaded, so the size of bit segment A is 8 bytes.

  • Another example:
#include<stdio.h>
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	printf("%d\n", sizeof(struct S));//3
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

At this time, a is of char type. First open 1 byte, a occupies 3 bits, and there are 5 left, b occupies 4 bits, and 1 bit is left, and the 5 bits that are not enough for c are opened, and then 1 is opened. A byte is assigned to c with 5 bits, and there are 3 left, which is not enough for d, and it is enough to open up 1 more byte. To sum up, the size of 3 bytes is opened at this time. This situation is a waste of space. That 1 bit is wasted, but there is no way.

  • Bit segments can save space to a certain extent, but also a moderate waste of space (small).
  • Draw a picture to explain the specific space development situation:

In order to prove the conclusion in the figure, turn on monitoring in the VS compiler and look at the memory:

1.3. Cross-platform problems of bit segment

  • Bit fields themselves are not cross-platform for the following reasons:
  1.  It is indeterminate whether an int bit field is treated as signed or unsigned.
  2.  The maximum number of bits in the bit field cannot be determined. (16-bit machine has a maximum of 16bit, 32-bit machine has a maximum of 32bit, written as 27bit, there will be problems on a 16-bit machine)
  3.  Whether members in a bit field are allocated in memory from left to right or right to left is undefined.
  4.  When a structure contains two bit fields, and the members of the second bit field are too large to fit in the remaining bits of the first bit field, it is uncertain whether to discard the remaining bits or to use them.
  • Summarize:

Compared with the structure, the bit segment can achieve the same effect, but it can save space very well, but there are cross-platform problems.

1.4, the application of bit segment

  •  Compared to structure, bit segment can achieve the same effect, but can save space very well, even if there are cross platform problems.

2. Enumeration

  • Enumeration, as the name suggests, is an enumeration. List the possible values.

  • For example in our real life:
  1. Monday to Sunday of the week is limited to 7 days, which can be listed one by one.
  2. Gender is: male, female, confidential, you can also list them one by one.
  3. There are 12 months in the month, you can also list them one by one
  • This is where enumerations can be used.
  • Note: The size of the enum type is always 4 bytes

2.1, the definition of enumeration type

#include<stdio.h>
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
int main()
{
	printf("%d %d %d %d %d %d %d\n", Mon, Tues, Wed, Thur, Fri, Sat, Sun);
	return 0;
}

The enum Day defined above is an enumeration type. The content in { } is the possible values ​​of the enumeration type, also called the enumeration constant. From the running results, it is not difficult to find that the enumeration has an initial value. By default, the first enumeration constant is 0, and the downward order is +1. Of course, the initial value can also be assigned when defining.

  • E.g:
#include<stdio.h>
enum Day//星期
{
	Mon = 1,
	Tues,
	Wed,
	Thur = 3,
	Fri = 8,
	Sat,
	Sun = 0
};
int main()
{
	printf("%d %d %d %d %d %d %d\n", Mon, Tues, Wed, Thur, Fri, Sat, Sun);
	return 0;
}

2.2, the advantages of enumeration

#define MALE 4
#define FEMALE 5
#define SECRET 6

typedef enum Sex
{
	MALE=4,
	FEMALE,
	SECRET
}Sex;
  • We can use #define to define constants, why use enums?
  • Advantages of enumeration:
  1.  Increase code readability and maintainability
  2.  Enumerations are type-checked and more rigorous compared to identifiers defined by #define.
  3.  Prevents naming pollution (encapsulation)
  4.  easy to debug
  5.  Easy to use, you can define multiple constants at a time

2.3, the use of enumeration

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5; //ok??  err错误,左右类型不一致

3. Union

3.1. Definition of union types

  • Unions are also a special custom type

Variables defined by this type also contain a series of members, characterized by the fact that these members share the same space (so the union is also called a union).

#include<stdio.h>
//联合类型的声明
union Un
{
	char c; //1
	int i;  //4
};
int main()
{
	//联合变量的定义
	union Un u;
	//计算联合变量的大小
	printf("%d\n", sizeof(u)); //4
	return 0;
}
  • The access to the union is similar to that of the structure, and the . operator or the -> pointer operator can be used.
union un x;
x.a = 10;
union un* p = &x;
p->a;

3.2, the characteristics of the joint

The members of the union share the same memory space, so the size of such a union variable is at least the size of the largest member (because the union must at least be able to save the largest member)

#include<stdio.h>
union Un
{
	char c; //1
	int i;  //4
};
int main()
{
	union Un u;
	//计算联合变量的大小
	printf("%d\n", sizeof(u)); 
	printf("%p\n", &u);
	printf("%p\n", &u.c);
	printf("%p\n", &u.i);
	return 0;
}

  • Using the spatial distribution of the union, the size end can be judged skillfully:
#include<stdio.h>
union un
{
	int a;
	char b;
};
int main()
{
	union un x;
	x.a = 1;
	if (x.b == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}
  •  Parse:

Here we need to save a set of binary sequences 0x 00 00 00 01 in the space corresponding to a. At this time, each of the four bytes has an address, and the address has a high and low level, and our data is 1bit corresponding to the byte. When dividing, the data has high and low weight bits, so there are two storage schemes, one with high weight bits at high addresses, and low weight bits at low addresses, such as the left storage method in the above figure, 01 is placed at the low address. The second scheme is the opposite. As shown on the right side of the above figure, 01 is placed at the high address, because b is always at the low address of a, and b occupies one byte, as shown in the figure above. xb=1 The red marker is divided , if the storage scheme is the first, then b=1, if it is the second, then b=0, and the first storage scheme is the storage rule of little-endian, and the second is the storage rule of big-endian.

It is known by the compiler that it is little endian:

3.3. Calculation of joint size

  1. The size of the union is at least the size of the largest member.
  2. When the maximum member size is not an integer multiple of the maximum alignment number, it must be aligned to an integer multiple of the maximum alignment number.
  • E.g:
#include<stdio.h>
union Un1
{
	char c[5];
	int i;
};
union Un2
{
	short c[7];
	int i;
};
int main()
{
	printf("%d\n", sizeof(union Un1)); //8
	printf("%d\n", sizeof(union Un2)); //16
	return 0;
}
  • Parse Un1 as size 8:

Because the size of the char type itself is 1 byte, and the default alignment number of the compiler is 8 bytes, the smaller value of the alignment number is 1 byte, the size of the int type itself is 4 bytes, and the smaller value of the alignment number is 4 bytes . At this time, the maximum alignment number is 4 bytes, and char c[5] represents at least 5 bytes in size, and because it is an integer multiple of the maximum alignment number 4, it is increased to 8 bytes.

  • Explain the size of Un2 16 bytes:

short c[7] means that the size of the union is at least 14 bytes, the size of the short type itself is 2 bytes, the default alignment number of the compiler is 8 bytes, the smaller value is 2 bytes, the int type itself is 4 bytes, compile The number of alignment is 8 bytes, the smaller value of this alignment is 4 bytes, the maximum alignment is 4 bytes, and 14 is not an integer multiple of 4, so it is increased to 16 bytes.

Guess you like

Origin blog.csdn.net/bit_zyx/article/details/122685180