Custom type: structure, enumeration, joint detailed introduction

Structure

Structure declaration

Basic knowledge of structure

A structure is a collection of values, and these values ​​become member variables. Each member of the structure can be a variable of different types.

Structure declaration

struct tag {
    
    
	member-list;
}variable-list;

If you describe a student:

struct Stu {
    
    
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
}//分号不能丢

Special statement

When declaring the structure, you can declare it incompletely.
such as:

//匿名结构体类型
struct
{
    
    
	int a;
	char b;
	float c;
}x;
struct
{
    
    
	int a;
	char b;
	float c;
}a[20], *p;

The two structures above omit the structure tag when they are declared.
So the question is coming?

//在上面代码的基础上,下面的代码合法吗?
p = &x;

Warning : The compiler will treat the above two declarations as two completely different types. So it is illegal.

Structure self-referencing

Is it possible to include a member whose type is the structure itself in the structure?

//代码1
struct Node
{
    
    
int data;
struct Node next;
};
//可行否?
//如果可以,那sizeof(struct Node)是多少?

In this way, we don’t know the size of the internal structure, so we can’t open up space, so I should use pointers. The correct sub-reference method is:

//代码2
struct Node
{
    
    
int data;
struct Node* next;
};

Definition and initialization of structure variables

With structure types, how to define variables is actually very simple.

struct Point
{
    
    
	int x;
	int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {
    
    x, y};
struct Stu //类型声明
{
    
    
	char name[15];//名字
	int age; //年龄
};
struct Stu s = {
    
    "zhangsan", 20};//初始化
struct Node
{
    
    
	int data;
	struct Point p;
	struct Node* next;
}n1 = {
    
    10, {
    
    4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {
    
    20, {
    
    5, 6}, NULL};//结构体嵌套初始化

Structure memory alignment

We have mastered the basic use of structures. Now let’s talk about another important question, which is also an important test point:Structure memory alignment

First, you must master the alignment rules of the structure :

  1. The first member is at an address with an offset of 0 from the structure variable.
  2. Other member variables should be aligned to an address that is an integer multiple of a certain number (alignment number).
    **Alignment number = the smaller value of the compiler default alignment number and the member size. **The default value in VS is 8
  3. The total size of the structure is an integer multiple of the maximum alignment (each member variable has an alignment).
  4. If the structure is nested, the nested structure is aligned to an integer multiple of its maximum alignment, and the overall size of the structure is an integer multiple of all maximum alignments (including the alignment of nested structures).
//练习1
struct S1
{
    
    
	char c1;//自身对其数为1
	int i;//自身对其数为4,之前是1没有对其所以+3,对其之后+4=8
	char c2;//自身对其数为1,对其了所以是+1.总的为9,因为要使得结构体总体的大小是最大对其数的整数倍,所以+3=12.
};
printf("%d\n", sizeof(struct S1));

Insert picture description here

//练习2
struct S2
{
    
    
char c1;//自身对其数为1,对其了
char c2;//自身对其数为1,一样对其了。总大小累计为2
int i;//自身对其数为4,所以之前的2没有对其,所以先对其为2+2,在加4就是8.
};
printf("%d\n", sizeof(struct S2));
//练习3
struct S3
{
    
    
double d;//自身对其数为8
char c;//8+1
int i;//未对其先加3在加4=>16
};
printf("%d\n", sizeof(struct S3));
//练习4-结构体嵌套问题
struct S4
{
    
    
char c1;//自身对其数为1
struct S3 s3;//结构体大小为16,最大对其数为8。1+7+16
double d;//24+8=32
};
printf("%d\n", sizeof(struct S4)); 

Insert picture description here

Why is there memory alignment?

Most of the references say this:

  1. Platform reason (transplant 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; while aligned memory access only requires one access.

In general:
the memory alignment of the structure is a practice of trading space for time.
When designing the structure, we must not only satisfy the alignment, but also save space. How to do it:
Let the members who occupy the small space be gathered as much as possible.

//例如:
struct S1
{
    
    
	char c1;//1
	int i;//3+4
	char c2;//1+3======12
};
struct S2
{
    
    
	char c1;//1
	char c2;//1
	int i;//2+4=====8
};

The members of type S1 and S2 are exactly the same, but the size of the space occupied by S1 and S2 is somewhat different.

Modify the default alignment

We have seen ==#pragma== this preprocessing directive before, and we use it again here to change our default alignment.

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
    
    
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为8
struct S2
{
    
    
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
    
    
//输出的结果是什么?
	printf("%d\n", sizeof(struct S1));//12
	printf("%d\n", sizeof(struct S2));//6
	return 0;
}

Conclusion:
When the alignment of the structure is inappropriate, we can change the default alignment by ourselves.

Structure parameter transfer

Just look at the code:

struct S
{
    
    
	int data[1000];
	int num;
};
struct S s = {
    
    {
    
    1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
    
    
	printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
    
    
	printf("%d\n", ps->num);
}
int main()
{
    
    
	print1(s); //传结构体
	print2(&s); //传地址
	return 0;
}

Which of the above print1 and print2 functions is better?
The answer is: the print2 function is preferred. Reason: When the
function is passed, the parameters need to be pushed onto the stack, which will cause system overhead in time and space.
If the structure is too large when passing a structure object, the system overhead of parameter stacking is relatively large, so it will cause performance degradation.
Conclusion: When passing the structure parameter, the address of the structure must be passed.

Bit segment

After the structure is finished, you have to talk about the realization of the structureBit segmentAbility.

What is a rank?

The declaration and structure of bit segments 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.

such as:

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

A is a bit segment type.
What is the size of that segment A?

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

Insert picture description here

Bit segment memory allocation

  1. The members of the bit segment can be int unsigned int signed int or char (belonging to the integer family) type
  2. The space of the bit segment is opened up in 4 bytes (int) or 1 byte (char) as needed.
  3. Bit segments involve many uncertain factors. Bit segments are not cross-platform. Programs that focus on portability should avoid using bit segments.
//一个例子
struct S
{
    
    
	char a:3;
	char b:4;
	char c:5;
	char d:4;
};
struct S s = {
    
    0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
//空间是如何开辟的?

Insert picture description here

Cross-platform issues

  1. It is uncertain whether the int bit field is treated as a signed number or an unsigned number.
  2. The number of largest bits in the bit segment cannot be determined. (The 16-bit machine is up to 16, and the 32-bit machine is up to 32, written as 27, which will cause problems on 16-bit machines.
  3. The members in the bit segment are allocated from left to right in memory, or the criteria for allocation from right to left have not been defined.
  4. When a structure contains two bit segments, and the member of the second bit segment is relatively large and cannot fit in the remaining bits of the first bit segment, it is uncertain whether to discard the remaining bits or use them.

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

Segment application

Insert picture description here

enumerate

Enumeration, as the name implies, enumerates one by one.
List the possible values ​​one by one.
For example, in our real life:

一周的星期一到星期日是有限的7天,可以一一列举。
性别有:男、女、保密,也可以一一列举。
月份有12个月,也可以一一列举

Enumeration can be used here.

Definition of enumerated type

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

Defined aboveenum Dayenum Sex, == enum Color== are all enumerated types. The content in {} is the possible value of enumeration type, also called enum constant.
These possible values ​​are all valued. By default, they start from 0 and increase by 1 at a time. Of course, you can also assign initial values ​​when defining them. E.g:

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

Advantages of enumeration

Why use enumeration?
We can use #define to define constants. Why do we have to use enumerations? Advantages of enumeration:

  1. Increase the readability and maintainability of the code
  2. Compared with the identifier defined by #define, the enumeration has type checking, which is more rigorous.
  3. Prevents name pollution (encapsulation)
  4. Easy to debug
  5. Easy to use, multiple constants can be defined at one time

Use of enum

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

Union (union)

Definition of union type

Union is also a special custom type. 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 union). such as:

//联合类型的声明
union Un
{
    
    
char c;
int i;
};
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));

Joint characteristics

The members of the union share the same memory space. 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 store 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);

Here you can also judge the big and small end.

Calculation of joint size

  • The size of the union is at least the size of the largest member
  • When the maximum member size is not an integer multiple of the large alignment number, it must be aligned to an integer multiple of the maximum alignment number.

such as;

union Un1
{
    
    
char c[5];
int i;
};
union Un2
{
    
    
short c[7];
int i;
};
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));//4
printf("%d\n", sizeof(union Un2));//14+2===16

Guess you like

Origin blog.csdn.net/weixin_45532227/article/details/111269726