bit-segment union enumeration

Insert image description here

Hello, long time no see. What I’m sharing today is the continuation of what I didn’t finish sharing about structures last time. This time we’ll talk about the concepts of bit-segment enumerations and unions and their usage.

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

In general, the bit segment is very similar to the structure, but the difference is that the size it represents is bits, and the size is bits, not bytes. The function of this is to reduce the memory size and increase efficiency.

Then let’s look at a bit end

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

This is the basic look of our bit field, a colon plus a number. The number represents the size, and the unit is bits.
We can also put it into a function to see its size.
We can put them into our function and use sizeof to test, see the following code

#include<stdio.h>
struct A
{
    
    
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
    
    
	printf("%zd ", sizeof(struct A));
	return 0;
}

We can see that the result of the above code on our console is
Insert image description here
the memory allocation of the 8-bit segment

  1. 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 allocated in 4 bytes (int) or 1 byte (char) as needed.
  3. Bit segments involve many uncertainties. Bit segments are not cross-platform. Programs that focus on portability should avoid using bit segments.
//一个例子
#include<stdio.h>

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;
}
//空间是如何开辟的?

Let’s take a look at the above example to understand how it opens up space on VS.

Because Vs is little endian, we start from the low address and move backward. Assume that we start with the low bit of the data and move backward.
Insert image description here
We are guessing based on its size, because the byte size it occupies is three bytes, so we guess it starts from the low bit of the data, and we do not need to use every byte. When the size of the following bits cannot be stored in one byte, we jump to the following byte and start using it. We can use the memory in VS to view our results.

Insert image description here
Converted to hexadecimal, it is the number 620304. Let’s take a look at the storage in memory now.

Insert image description here

The results we can see are the same as those on our compiler, but there are still problems, that is, the bit segment cannot be cross-platform. The first is because it has a lot of uncertainties. For example, we don’t know what it does to the data. How to use it, whether it is from small to large or from left to right, is uncertain, so it has a lot of uncertainty

2.3 Cross-platform issues in bit segments

  1. It is undefined whether an int bit field is treated as a signed or unsigned number.
  2. The maximum number of bits in a bit field cannot be determined. (The maximum number for a 16-bit machine is 16, and the maximum number for a 32-bit machine is 32. Writing it as 27 will cause problems on a 16-bit machine.
  3. The criteria for whether members of a bit field are allocated from left to right or right to left in memory are undefined.
  4. When a structure contains two bit fields, and 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 the remaining bits should be discarded or used.

Summary:
Compared with structure, bit segments can achieve the same effect, but can save space very well, but there are cross-platform problems.
Insert image description here
This is the usage scenario of our bit segment, which is equivalent to packaging data. For example, when we send a message on WeChat and want to confess to a girl, we first need to determine the username of the girl, which is equivalent to the IP address in our picture. If Without this IP address, we may not know who to send it to. We may send it to our good brothers, which will cause a big misunderstanding. And our data is not sent directly, and we need to do our final packaging. Yes, when we package, if we do not use bit segments, the above version requires an integer size for each one, so it is not a waste. The larger the space we occupy, the slower the running speed. We will send The data passes through the network protocol stack, which is equivalent to our highway. If it is packaged in int, it is equivalent to a large truck, but if it is packaged in bit segments, it is equivalent to a small car, and the traffic speed is Soon.

3. Enumeration

Enumeration, as the name suggests, means enumerating items one by one.
List the possible values ​​one by one.
For example, in our real life:
Monday to Sunday are a limited number of 7 days in a week, and they can be listed one by one.

Gender includes: male, female, confidential, or you can list them one by one.
There are 12 months in the month, and they can also be listed one by one.
You can use enumeration here.

Then let’s use enumerations (the enumeration keyword is enum).
Insert image description here
We can see that enumerations are actually integer constants. Speaking of constants, do you remember how many there are? One is a literal constant, and the other is a long constant modified by const. Variables, and enumeration constants
3.2 Advantages of enumerations
Why use enumerations?
We can use #define to define constants, why do we have to use enumerations?
Advantages of enumerations:

  1. Increase code readability and maintainability
  2. Compared with identifiers defined by #define, enumerations have type checking, which is more rigorous.
  3. Prevented naming pollution (encapsulation)
  4. Easy to debug
  5. Easy to use, multiple constants can be defined at one time

Here we are going to talk about our often beautiful define. We can also talk about the above three elements written as

#define GREEN 0
#define RED 0
#define BLUE 0

But why is enumeration convenient for debugging? There is a reason. When we define, we directly replace it when debugging, so it is inconvenient to debug. You call enumeration convenient for debugging, and it is also convenient. For example, if we want to enumerate A week, then we can just write it directly, but if we define it, we have to write it seven times, which seems a bit troublesome, so it is not recommended to write it like this.

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

We can write like this in C language, but we cannot write like this in C++ with strict syntax checking.
4. Union (union)

  • 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 the union is also called a union).

4.2 Characteristics of Unions
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).

#include<stdio.h>
//联合类型的声明
union Un
{
    
    
	char c;
	int i;
};

int main()
{
    
    
	//联合变量的定义
	union Un un;
	//计算连个变量的大小
	printf("%d\n", sizeof(un));
	return 0;
}

By running, we found that our result is 4 bytes in size, which means that our char actually shares one byte with our int.
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 save at least the largest member)

union Un
{
    
    
 int i;
 char c;
};
union Un un;
// 下面输出的结果是一样的吗?
printf("%d\n", &(un.i));
printf("%d\n", &(un.c));
//下面输出的结果是什么?
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);

What you can see is that their addresses are actually the same, which further illustrates that the consortium shares the same space.

Then do we still remember how we calculated the big and small endian of the machine before we tested it? I believe some people remember it and others forgot it, so let’s write it down again.

#include<stdio.h>
int check_sys()
{
    
    
	int a = 1;
	return *((char*)&a);
}
int main()
{
    
    
	int ret = check_sys();
	if (ret == 1)
	{
    
    
		printf("小端\n");
	}
	else
	{
    
    
		printf("大端\n");
	}
	return 0;
}

Now we can also use the consortium for testing

#include<stdio.h>
int check_sys()
{
    
    
	union
	{
    
    
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;
}
int main()
{
    
    
	int ret = check_sys();
	if (ret == 1)
	{
    
    
		printf("小端\n");
	}
	else
	{
    
    
		printf("大端\n");
	}
	return 0;
}

The scope of use of the consortium is a bit small, and it is only used in special circumstances. Let’s take a look at the picture below.

Insert image description here
Here we look at the picture and find that we need to redefine a structure every time, which wastes a lot of space. Then we can write it like this

Insert image description here
Writing this way can save a lot of space, so I’ll share today’s content here. See you next time.

Guess you like

Origin blog.csdn.net/2301_76895050/article/details/133198572