Custom types: structure, enumeration, union (2)

2. bit segment

The appearance of bit segments is to save space.

2.1 What is a bit segment?

The declaration and structure of the bit field are similar, with two differences:
1. The members of the bit field must be int, unsigned int or signed int.
2. There is a colon and a number after the member name of the bit field.

for example:

struct A
{
   int _a:2;
   int _b:5;
   int _c:10;
   int _d:30;
};

 A is a bit field type. The bits of the bit field refer to binary bits. The number after the member name represents how many bits occupy the space. _a occupies 2 bits and _b occupies 5 bits. .
What is the size of segment A?

If this A is a structure, it will occupy at least 16 bytes, but if it is a bit field, it will occupy 8 bytes. Why is this?

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{

    printf("%d\n", sizeof(struct A));
	return 0;
}

 2.2 Memory allocation of bit segments

1. The members of the bit field can be int unsigned int signed int or char (belonging to the integer family) type
2. The space of the bit field is 4 words as needed It is opened in section (int) or 1 byte (char) format.
3. Bit segments involve many uncertain factors. Bit segments are not cross-platform. Programs that focus on portability should avoid using bit segments.

 We use the above code to pre-open the space. Because the members are all ints, we first open an integer type, 4 bytes, 32 bits. Then _a first occupies 2 bits, then this Are the 32 bits used from left to right or right to left?? This is uncertain, so the bit segment is not cross-platform, and different compilers may differ. When we have used 30 bits, there are 2 bits left, but the next member needs to use 6 bits, so should the remaining 2 bits be used< /span>. uncertain? If not used, it will be wasted. If used, 4 bits need to be opened, which is also

 

 Even if there are more uncertainties, we can still explore how it is used on vs.

In this structure type S, a occupies 3 bits, b occupies 4 bits, c occupies 5 bits, and d occupies 4 bits. After s is created, it is assigned a value of 0. Put 10 and b in a. Put a 12 in it, a 3 in c, and a 4 in d. Next we will analyze.

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

Since the members are all of char type, they are allocated one byte at a time. You first open up a byte in the memory and start storing a. A occupies 3 bits.Suppose uses the low bit first, a occupies 3 bits, and then b occupies 4 bits, then occupies 4 bits to the left, and then the first byte is still There is one bit left. It is not enough to store c, so open up a byte again, If you use the remaining bits in the first byte, then only one byte is needed to store c and d. If not used, another byte needs to be allocated. .

Let's test it out and see what it's like. The result is 3, so the remaining byte is wasted.

 

  a can only use 3 bits, so you can only store the last three bits of 10 in binary, which is 010, b is 1100, c is 00011, and d is 0100. If converted to hexadecimal, it is 6, 2 ,0,3,0,4.

 

 

 Through debugging, we found that this is the case, so our guess is correct. The memory is used from low to high. At the same time, when the remaining space is not enough for the next member, it is directly wasted and new space is opened up.

2.3 Cross-platform issues in bit segments

1. It is undefined whether the int bit field is regarded as a signed number or an unsigned number.
2. The maximum number of bits in the bit field cannot be determined. (The maximum limit for a 16-bit machine is 16, and the maximum limit for a 32-bit machine is 32. Writing it as 27 will cause problems on a 16-bit machine.
3. Are the members in the bit segment allocated from left to right in the memory? The right-to-left allocation standard has not been defined.
4. When a structure contains two bit fields, the members of the second bit field are larger and cannot fit in the remaining bits of the first bit field. , it is uncertain whether to discard the remaining bits or use them.

Summarize:

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

2.4 Application of bit segments

When we transmit data, we need to encapsulate the data. We may need to wrap a series of data on the data, like the above.

Faced with data like the above, it is very convenient to use bit segments, which are exactly 32 bits and can save space.

When the data is relatively large, the burden on the network is relatively large. When the data is relatively small, except for the data that is actually to be transmitted, the other data is very small, the burden on the network is relatively small, and the efficiency is relatively high.


3. Enumeration

An enumeration, as its name implies, is to list one by one.
List the possible values ​​one by one.
For example, in our real life:

There are a limited number of 7 days from Monday to Sunday in a week and can be listed one by one.
Gender includes: male, female, confidential, you can also list them one by one.
There are 12 months in the month, and you can also list them one by one.

Enumerations can be used here.

3.1 Definition of enumeration types

enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};
enum Color//颜色
{
	RED,
	GREEN,
	BLUE
};

The enum Day , enum Sex , and enum Color defined above are all enumeration types.
The contents in {} are possible values ​​of the enumeration type, also called enumeration constants.
These possible values ​​are all valid, starting from 0 by default and increasing by 1 at a time.

So when we want to modify the constant value in the main function, it is not possible because it is a constant.


Of course, an initial value can also be assigned when defining. For example:

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};

3.2 Advantages of enumerations

Why use enumerations?

We can use #define to define constants, why do we have to use enumerations?

Advantages of enumeration:
1. Increase code readability and maintainability
2. Compare with identifiers defined by #define Enumerations have type checking, which is more rigorous.
3. Prevents naming pollution (encapsulation)
4. Easy to debug
5. Easy to use, multiple definitions can be defined at one time constant

 3.3 Use of enumerations

Although the value of an enumeration variable cannot be changed, the enumeration variable can be assigned a value initially.

enum Color//颜色
{
  RED=1,
  GREEN=2,
  BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

So what is the memory size occupied by enumeration variables?

enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};
int main()
{
	enum Sex sex = FEMALE;
	printf("%d\n", sizeof(sex));
	return 0;
}

 

 In fact, the size of the enumeration variable is the size of an integer.


4. Union (community)

4.1 Definition of union types

Union is also a special custom type
The variables defined by this type also contain a series of members. The characteristic is that these members share the same space (so union is also called shared body).
For example:

//联合类型的声明
union Un
{
	char c;
	int i;
};
//联合变量的定义
union Un un;

If we want to calculate the size of the union, then int is 4 bytes and char is 1 byte. Is the answer like this?

4.2 Characteristics of the Union

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

If we want to calculate the size of the union, then int is 4 bytes and char is 1 byte. Is the answer like this?

union Un
{
	char c;
	int i;
};
int main()
{
	union Un un;//联合变量的定义
	printf("%d\n", sizeof(union Un));
	return 0;
}

 Why is this?

When we print out the addresses of un and its members, we find that the addresses are the same.

union Un
{
	char c;
	int i;
};
int main()
{
	union Un un;//联合变量的定义
	printf("%p\n", &un);
	printf("%p\n", &(un.c));
	printf("%p\n", &(un.i));
	return 0;
}

 

i occupies 4 bytes, c occupies one byte, and the addresses are the same, so are the first byte of i and the first byte of c the same space? In other words, sharing a space?

 The answer is right, so the union is also called a community. But they will affect each other, and changing one will change the others.

So the size of the unionis at least the size of the largest member before it can save data.

So what is the use of a consortium?

The union can be used to determine whether the current machine is big endian or little endian. When the low-order data of the data is placed at the low address of the memory, it is called little-endian storage. When the low-order data of the data is placed at the high address of the memory, it is called big-endian storage.

I wrote a judgment code before as follows:

int check_sys()
{
	int a = 1;
	if (*(char*)&a == 1)
		return 1;
	else
		return 0;
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");

	return 0;
}

Simplified as follows:

int check_sys()
{
	int a = 1;
	return *(char*)&a;//返回1表示小端,返回0表示大端
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");

	return 0;
}

Now we use union to judge:

First, we create a union variable u. When we assign a value of 1 to i, then getting the value of c means getting the first byte of data of i, then return c can get the result.

int check_sys()
{
	union
	{
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;//返回1表示小端,返回0表示大端
}

int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

4.3 Calculation of union size

The size of the unionis at least the size of the largest member.
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.

for example:

In Un1, c is 5 bytes and i is 4 bytes. Why is Un1 8 bytes? 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. c is an array. The maximum alignment number is calculated by element, which is equivalent to placing 5 char type variables. Then the maximum alignment number is 1, and the maximum alignment number of i is 4, then 3 bytes are wasted, which is 8.

In Un2, c is 7 bytes and i is 4 bytes, so why is Un2 16 bytes? c is an array of short type, the maximum alignment number is 2, and the maximum alignment number of i is 4, but c occupies 14 bytes, so it is 16.

union Un1
{
	char c[5];
	int i;
};
union Un2
{
	short c[7];
	int i;
};
int main()
{
	printf("%zd\n", sizeof(union Un1));
	printf("%zd\n", sizeof(union Un2));
	return 0;
}

The conditions for the use of the consortium are very strict, so when should it be used?

That is when some members will not be used at the same time.


Today’s sharing ends here! Thanks for reading, folks, and see you in the next issue.

Guess you like

Origin blog.csdn.net/2301_79035870/article/details/133816224