[C language] ☀️Custom type (structure + bit segment + enumeration + union) [recommended collection]

content

1. Structure

Why is there a structure?

struct declaration

Basic knowledge of structure

struct declaration

Self-referencing of structs

Definition and initialization of structure variables

access to structure members

1. Structure objects. Structure members

 2. Structure pointer -> structure member

structure parameter 

Structure memory alignment

 Alignment rules

Why does memory alignment exist?

Modify the default alignment

Second, the segment

What is a bit segment

Memory allocation for bit fields

Cross-platform issues with bit fields

Application of Bit Segments

3. Enumeration constants

What is an enumeration?

Definition of enumeration types

What is the value?

Advantages of enumeration types

4. Union (community)

Definition of Union Types

declaration of union type


1. Structure

Why is there a structure?

The data types we learned earlier: char, int, double, and pointers are not enough to represent objects . If we want to represent a person, can we use a number to represent it? It is definitely not possible. It is necessary to know that people are complex objects and cannot be simply represented by a certain number. To represent a person, many aspects are needed, such as name, gender, age, etc. To represent people, we have to create a complex type, and there is a struct type in C language

Structure is a particularly important knowledge point in C language. Structure enables C language to describe complex types.

The structure type also needs to be created by the word

struct declaration

Basic knowledge of structure

A struct is a collection of values ​​called member variables, each member of the struct can be a variable of a different type

struct declaration

Describe a person:

Way 1:

struct Peo     //声明了一个结构体类型
{
	char name[20];
	int age;
};

This is the declaration of the structure, struct is the structure keyword, Peo is the structure label (structure type name), and the curly brackets are the structure member variables

Structure members can be scalars, arrays, pointers, structures

 Way 2:

struct Peo
{
	char name[20];
	int age;
}p1, p2   //全局变量

Method 2 is to create two structure variables of type struct Peo when the structure is declared, but it should be noted that p1 and p2 obtained by this creation method are global variables with a wide scope, which is generally not recommended. Write

Mode 3 (anonymous struct type)

struct 
{
	char name[20];
	int age;
}p1, p2;
struct 
{
	char name[20];
	int age;
}p1;
struct 
{
	char name[20];
	int age;
}*p;

The first code directly omits the structure label (structure type name), so that the p1 and p2 structure variables can only be created after the structure is created, and cannot be created in the following main function. Relatively limited, not recommended

The second code creates a pointer p later, but if on the basis of the second code, it is illegal to write p = &p1; below, and the compiler will treat the above two declarations as two completely different types . So it's illegal

Self-referencing of structs

When we use the structure, can we write the structure in the structure when declaring the structure

The following code:

struct Peo
{
	char name[20];
	int age;
	struct Peo next;
};

It should be noted that this is not acceptable, because if it is written like this, what should be the size of the structure? I'm sure it won't come out

Correct spelling

struct Peo
{
	int data;
	struct Peo* next;
};

Put a structure pointer of the same type in the structure

Definition and initialization of structure variables

How to define structure variables, see the following code:

Code 1:

#include <stdio.h>
#include <string.h>
struct Peo
{
	char name[20];
	int age;
};
int main()
{
	struct Peo p = { "张三",18 };   //通过结构体类型来创建结构体变量并初始化
	printf("%s  %d\n", p.name, p.age);
	//修改里面的内容
	strcpy(p.name, "李四");
	p.age = 20;
	printf("%s  %d\n", p.name, p.age);
	return 0;
}

Through this code, a structure describing a person is created and initialized, and the content in it is modified later

analogy:

In fact, using a structure is equivalent to building a house. The previous statement of the structure is the drawing of the drawing, and the later creation of the structure variable is to build the house according to the drawing.

So when we declare a structure, the system will not allocate space to it. Only after the structure variable is created will the system allocate space to it.

Code 2 (create a global structure variable)

struct Peo
{
	char name[20];
	int age;
}p1,p2,p3;

When the structure is declared, write the name/label of the structure variable to be created directly after the curly braces, but it should be noted that the global variable is created here. It is recommended to use this method less.

access to structure members

1. Structure objects . Structure members

The following code accesses the structure members through the structure variable name/label

struct Peo
{
	char name[20];
	int age;
};
int main()
{
	struct Peo p = { "张三",18 };
	printf("%s   %d\n", p.name, p.age);
	return 0;
}

operation result:

 2. Structure pointer -> structure member

 The following code: Access structure members through structure pointers

#include <stdio.h>
struct Peo
{
	char name[20];
	int age;
};
int main()
{
	struct Peo p = { "张三",18 };
	struct Peo* ps = &p;
	printf("%s   %d\n", ps->name, ps->age);
	return 0;
}

operation result:

structure parameter 

 Structure parameter transfer is divided into value transfer and address transfer

1. Pass by value

The following code:

struct Peo
{
	char name[20];
	int age;
};
void print1(struct Peo p)
{
	printf("%s   %d\n", p.name, p.age);
}
int main()
{
	struct Peo p = { "张三",18 };
	print1(p);   //传值,传整个结构体过去
	return 0;
}

This is to pass the entire structure directly

2. Address

struct Peo
{
	char name[20];
	int age;
};
void print2(struct Peo* ps)
{
	printf("%s   %d\n", ps->name, ps->age);
}
int main()
{
	struct Peo p = { "张三",18 };
	print2(&p);
	return 0;
}

Pass the address of the structure

For these two parameter passing methods, we prefer the second method

The reason is:

When passing parameters to a function, the parameters need to be pushed onto the stack. If a structure object is passed, the structure is too large, and the system overhead of parameter stacking is relatively large, so it will lead to performance degradation.

Structure memory alignment

If we want to calculate the memory size of a structure, how do we calculate it? Is it to add the memory size of all member variables directly?

First look at the following code:

#include <stdio.h>
struct P
{
	char a;
	int b;
};
int main()
{
	struct P p;
	printf("%d\n", sizeof(p));
}

 After creating the structure variable p here, find the size of this structure, is it 1+4==5?

operation result:

 The print result is 8, which obviously shows that the size of the structure is not a simple addition of member variables, so how did this 8 come from? This involves structure memory alignment

 Alignment rules

  1.  The first member is at the address at offset 0 from the struct variable (offset 0 from the starting position)
  2. The remaining other member variables should be aligned to an integer multiple of a certain number (alignment number)
  3. Alignment : The smaller of the size of each member itself and the default alignment of the compiler used
  4. The total size of the structure is an integer multiple of the maximum alignment number (each member variable has an alignment number)
  5. If a structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment number, and the overall size of the structure is an integer multiple of all maximum alignment numbers (including the alignment number of nested structures).

Tip: The default alignment number of the VS compiler is 8, and the gcc compiler under linux has no default alignment number

Then you can now use the alignment rules to find the size of the structure

In the above code, the first one in the structure is of type char, which is placed directly at offset 0

The second type is int type, its own size is 4, and the default alignment number is 8, so the alignment number takes the smaller value of 4

The total size of the structure is an integer multiple of the maximum alignment number

See by drawing

 So the size of this structure is 8

Why does memory alignment exist?

  1. Platform reason (transplantation reason): Not all hardware platforms can access any data at any address; some hardware platforms can only fetch certain types of data at certain addresses, otherwise a hardware exception will be thrown
  2. Performance reasons : Data structures (especially stacks) should be aligned on natural boundaries as much as possible. The reason is that in order to access unaligned memory, the processor needs to make two memory accesses; aligned memory accesses require only one access.

So structure memory alignment is to trade space for time

When designing the structure, we must not only satisfy the alignment, but also save space, so that the members that occupy the small space should be concentrated as much as possible.

Modify the default alignment

Just now we said that the default alignment number of the VS compiler is 8, but in fact this default alignment number can be modified

When the alignment of the structure is not suitable, we can change the default alignment by ourselves

#pragma pack()      //括号内放想达到的默认对齐数

The following code:

#include <stdio.h>
#pragma pack(4)    //修改默认对齐数为4
struct P
{
	char a;
	int b;
};
#pragma pack()    //取消设置的默认对齐数,还原为默认值
int main()
{
	struct P p;
	printf("%d\n", sizeof(p));
}

Note: This default alignment number cannot be modified at will, and the modified value must be 2^n (n==0,1,2,3...)

Second, the segment

What is a bit segment

C language allows to specify the length of memory occupied by its members in units of bits in a structure . Such members in units of bits are called "bit fields" or " bit fields ". Use bit fields to store data with fewer bits

as follows:

struct A
{
	int a : 2;
	int b : 3;
	int c : 5;
	int d : 10;
};

It can be seen from the code that the declaration of the bit field is very similar to the structure. The number after the colon indicates the size of the member (in bits). There are two differences:

  1. The members of the bit field must be int, unsigned int, or signed int 
  2. Bit fields have a colon and a number after the member name

So what is the size of this bit segment? Is it 2+3+5+10 bits? Definitely not, test it with code

struct A
{
	int a : 2;
	int b : 3;
	int c : 30;
	int d : 10;
};
int main()
{
	printf("%d\n", sizeof(struct A));
	return 0;
}

operation result:

  So how does this 12byte come from? Next, look at the memory allocation of the bit segment

Memory allocation for bit fields

  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 in the form of 4 bytes ( int ) or 1 byte ( char ) as needed
  3. Bit segment involves many uncertain factors, bit segment is not cross-platform, and programs that focus on portability should avoid using bit segment

There are 4 variables of type int in the declaration of the bit segment in the preceding code, which should have taken up 16 bytes of space, but only 12 bytes are occupied after the bit segment is used. The calculation method is as follows:

 When the requested memory is not enough, and the second bit segment member is too large to fit in the remaining bits of the first bit segment, it is uncertain whether to discard the remaining bits or use them, which depends on the compiler.

Cross-platform issues with bit fields

  1. It is indeterminate whether the 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 is up to 16, 32-bit machine is up to 32, written as 27, there will be problems on 16-bit machines
  3. Whether members in a bit field are allocated in memory from left to right or from right to left is undefined
  4. When a structure contains two bit segments, and the second bit segment member is too large to fit in the remaining bits of the first bit segment, it is uncertain whether to discard the remaining bits or use them

Application of Bit Segments

When we usually want to send a hello message to a friend, we not only send hello, but also send hello and other data together, such as who sent the message, to whom, and the target ip address Information, etc., but some of these information may only need a few bits to save, it would be too wasteful to use all int, which will also affect the network condition, in this case, use the bit segment

3. Enumeration constants

What is an enumeration?

Enumeration means enumerating one by one, enumerating all possible values.

For example, colors, weeks, and months can all be listed. In C language, the values ​​of a certain type we want are defined as enumeration types, and their values ​​can also be listed one by one.

Definition of enumeration types

For example, now list the three primary colors

enum Color
{
	RED,
	GREEN,
	BLUE
};

 The content in {} is the possible value of the enumeration type, also called the enumeration constant

What is the value?

So what are the values ​​here? The following code:

enum Color
{
	RED = 3,
	GREEN = 7,
	BLUE = 5
};
int main()
{
	printf("%d\n", RED);
	printf("%d\n", GREEN);
	printf("%d\n", BLUE);
}

print result:

These possible values ​​all have values, starting from 0 by default and incrementing by 1 at a time. Of course, the initial value can also be assigned when defining . as follows:

enum Color
{
	RED = 3,
	GREEN = 7,
	BLUE = 5
};

It can be used like this :

enum Color
{
	RED ,
	GREEN,
	BLUE
};
int main()
{
	enum Color c = RED;
}

Advantages of enumeration types

  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

4. Union (community)

Definition of Union Types

Union is 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 union is also called union)

declaration of union type

The following code:

union U
{
	char i;
	int a;
};

So what is the size of the union here ?

It is also the principle of alignment, slightly different

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)

The overall size is an integer multiple of the maximum number of alignments

-----------------------------------------------------------------

-------------The storage of C language floating point numbers in memory is completed---------

Regarding the C language, each knowledge point will be written in a separate blog for a more detailed introduction.

Welcome everyone to pay attention! ! !

Learn to communicate together! ! !

Let's get programming to the end! ! !

--------------It's not easy to organize, please support three consecutive -------------------

Guess you like

Origin blog.csdn.net/weixin_46531416/article/details/120379878