[C language study notes---custom type]

C language advanced custom type

Preface:
Through the advanced knowledge of string functions and memory functions in C language, this article will continue to learn about custom types in C language.

/ Summary of knowledge points /
Custom types in C language
1. Structure
2. Enumeration
3. Union

1. Structure

Structure : It is a collection of values. These values ​​are called member variables. Each member of the structure can be a variable of different types.
Array : It is a set of elements of the same type.

1.1. Declaration of structure

Format :

struct tag
{
    
    
	member list; //成员列表
}variable list; //结构体变量
#include <stdio.h>

struct Student
{
    
    
	char name[20];
	int age;
	char sex[5];
	float score;
}s1,s2,s3;//三个结构体变量 --- 全局变量

struct Book
{
    
    
	char name[20];
	char author[12];
	float price;
};
struct Book
{
    
    
	char name[20];
	char author[12];
	float price;
}b1;
int main()
{
    
    
	struct Student s4, s5, s6;//三个结构体变量 ---局部变量
	return 0;
}

A special declaration of a structure: structure anonymous

#include <stdio.h>
struct Student
{
    
    
	char name[20];
	int age;
	char sex[5];
	float score;
}s1,s2,s3;//三个结构体变量 --- 全局变量

//一种特殊声明,匿名声明,只会执行一次。一次性
struct 
{
    
    
	char name[20];
	char author[12];
	float price;
}b1;
struct 
{
    
    
	char name[20];
	char author[12];
	float price;
}*p;
int main()
{
    
    
	struct Student s4, s5, s6;//三个结构体变量 ---局部变量
	
	//不建议使用匿名写法
	p = &b1;
	return 0;
}

1.2. Self-reference of structure

Self-reference of a structure : It means that within the structure, a pointer to a structure of its own type is included
. Example of incorrect writing :

struct Node
{
    
    
	int data;//数据
	struct Node n;//下一个节点
};

Correct citation method :

//正确自引用写法1:
struct Node
{
    
    
	int data;//数据
	struct Node* n;//下一个节点
};

//正确写法2:
typedef struct Node
{
    
    
	int data;//数据
	struct Node* n;//下一个节点
}Node;

Summary :
It is not feasible for a structure to contain a structure of the same type, but it is feasible to contain a pointer structure of the same type.

1.3. Definition and initialization of structure variables

#include <stdio.h>
struct Point
{
    
    
	int x;
	int y;
}p1 = {
    
     1,2 };//初始化方式一
struct Point p3 = {
    
     4,5 };//初始化方式二
struct Stu
{
    
    
	char name[15];
	int age;
};
struct Node
{
    
    
	int data;
	struct Point p;
	struct NOde* next;
};
int main()
{
    
    
	int a = 3;
	int b = 4;
	struct Point p2 = {
    
     a,b };//初始化方式三
	
	struct Stu s = {
    
     "lisi",20 };//顺序初始化
	struct Stu s1 = {
    
     .age = 18,.name = "zhangsan" };//指定顺序或指定成员初始化
	printf("%s %d\n", s.name, s.age);
	printf("%s %d\n", s1.name, s1.age);

	struct Node n = {
    
     100,{
    
    3,4},NULL };
	printf("%d x=%d y=%d\n", n.data, n.p.x, n.p.y);
	return 0;
}

1.4. Structure memory alignment

#include <stdio.h>
struct S1
{
    
    
	char c1;
	int i;
	char c2;
};
struct S2
{
    
    
	char c1;
	char c2;
	int i;
};
int main()
{
    
    
	printf("%d\n", sizeof(struct S1));//12
	printf("%d\n", sizeof(struct S2));//8
	return 0;
}

offsetof - Macro - can be used directly
Prototype: size_t offsetof( structName, memberName );
Header file: <stddef.h>
Function: Calculate the offset of the structure member compared to the starting position

#include <stdio.h>
#include <stddef.h>
struct S1
{
    
    
	char c1;
	int i;
	char c2;
};
struct S2
{
    
    
	char c1;
	char c2;
	int i;
};
int main()
{
    
    
	//offsetof -- 计算起始位置的偏移量
	printf("%d\n", offsetof(struct S1, c1));//0
	printf("%d\n", offsetof(struct S1, c2));//8
	printf("%d\n", offsetof(struct S1, i));//4

	printf("%d\n", offsetof(struct S2, c1));//0
	printf("%d\n", offsetof(struct S2, c2));//1
	printf("%d\n", offsetof(struct S2, i));//4
	return 0;
}

Summary :
From viewing, you can see that the contents defined by the structure are exactly the same, but the byte sizes are different.
Principle: Structure memory alignment

1.5. Explore structure memory alignment

1. How to align?
2. Why do we need to align?

Standard provisions :
Rules for structure alignment :

1. The members of the structure start to be stored at an address with an offset of 0 from the structure variable.
2. Other member variables of the structure must be aligned to an address that is an integer multiple of a certain number (alignment number) and stored at
an alignment number = compiler The smaller of the default alignment number and the size of the member

Among them, the VS compiler defaults to 8. In Linux, the default is no alignment number. The alignment number is the size of the member itself (under the gcc compiler)

3. The total size of the structure is an integer multiple of the maximum alignment number (each member variable has an alignment number)
4. If the structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment number. , the overall size of the structure is an integer multiple of the maximum alignment number (including the alignment number of nested structures)

1. How to align?
According to the rules, the alignment offset is related to the type of the variable. The offset is first obtained based on the variable type and then compared with the default alignment number of 8 of the current VS compiler. The smallest one is selected as the alignment number of the variable, which is the storage The amount of space opened up by the space.
Finally, the total size of the structure must be an integer multiple of the maximum alignment number of all structure members. If it is not an integer multiple, space will continue to be opened until it becomes an integer multiple.

#include <stdio.h>
struct S1
{
    
    
	char c1;
	char c2;
	int i;
};
struct S2
{
    
    
	char c1;
	int i;
	char c2;
};
struct S3
{
    
    
	double d;
	char c;
	int i;
};

struct S4
{
    
    
	char c1;
	struct S3 s3;
	double d;
};
int main()
{
    
    
	printf("%d\n", sizeof(struct S1));//8
	printf("%d\n", sizeof(struct S2));//12
	printf("%d\n", sizeof(struct S3));//16
	printf("%d\n", sizeof(struct S4));//32
	return 0;
}

2. Why do we need to align?
(1) Platform reasons:
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 only require one access.

3. Generally speaking: the memory alignment of structures is aimed at exchanging space for time.
So if you want to not only satisfy alignment but also save space when designing a structure, how can you do it?
(1) Keep member variables that take up little space together as much as possible.

For example :

struct S1
{
    
    
	char c1;
	char c2;
	int i;
};
struct S2
{
    
    
	char c1;
	int i;
	char c2;
};

(2), quote #pragma, preprocessing instructions, modify the default alignment number

#include <stdio.h>
struct S1
{
    
    
	char c1;
	char c2;
	int i;
};
#pragma pack(1)//设置默认对齐数为1
struct S2
{
    
    
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为编译器默认值
int main()
{
    
    
	printf("%d\n", sizeof(struct S1));//8
	printf("%d\n", sizeof(struct S2));//6
	return 0;
}

Summary :
So when the structure alignment is inappropriate, you can also modify the default alignment number (usually an even number) through the #pragma preprocessing directive.

1.6. Structure parameter passing

Classification of structure parameter passing : structure call by value and call by address

#include <stdio.h>
struct S
{
    
    
	int data[1000];
	int num;
};
void print(struct S t)
{
    
    
	printf("%d %d %d %d\n", t.data[0], t.data[1], t.data[2], t.num);
}
void print2(struct S* ps)
{
    
    
	printf("%d %d %d %d\n", ps->data[0], ps->data[1], ps->data[2], ps->num);
}
int main()
{
    
    
	struct S s = {
    
     {
    
    1,2,3},100 };
	print(s);//传值调用
	print2(&s);//传值调用
	return 0;
}

Summary :
1. When a function passes parameters, the parameters need to be pushed onto the stack, which will cause system overhead in time and space.
2. If a structure object is passed and the structure is too large, the system overhead of pushing parameters onto the stack will be relatively large. Therefore, it will lead to a decrease in performance

2. Enumeration

As the name suggests, it lists the data one by one
and lists the possible values ​​one by one.

For example, some data in life that can be listed one by one:
1. There are seven days in a week, which can be listed one by one from Monday to Sunday.
2. There are male and female genders, which can be listed one by one.
3. There are 12 months in the month, which can be listed one by one. enumerate

2.1. Definition, use and initialization of enumeration types

#include <stdio.h>
//宏定义常量
#define MALE  1
#define FEMALE  2
#define SECRET  3
enum Sex
{
    
    
	//枚举的可能取值
	MALE,//注意,枚举常量以逗号隔开
	FEMALE,
	SECRET
};
enum Color
{
    
    
	//枚举的可能取值
	RED,
	GREEN,
	BLUE
};
enum Week
{
    
    
	Mon = 1,//赋初始值
	Tues = 2,
	wed = 3,
	Thur = 4,
	Fri = 5,
	sat = 6,
	Sun = 7
};
int main()
{
    
    
	//MALE = 5; ---- Error,因为枚举常量属于常量,不可以给常量赋值,常量是不可更改的
	printf("%d\n", MALE);//0
	printf("%d\n", FEMALE);//1
	printf("%d\n", SECRET);//2
	//枚举成员常量不赋予初值时,默认从0开始递增的

	//枚举类型的使用:
	enum Sex sex = SECRET;//相当于将一个常量赋值给变量sex
	//也类似于宏定义常量的使用
	printf("%d\n", sizeof(sex));//4,打印查看枚举常量的大小,整型4个字节
	
	return 0;
}

Summary :
We can use #define to define constants, so why use enumerations?
Advantages of enumeration :
1. Increase code readability and maintainability
2. Compared with identifiers defined by #define, enumeration has type checking, which is more rigorous
3. Easy to debug
4. Easy to use, multiple constants can be defined at one time

Differences in the use of enumeration types

#include <stdio.h>
enum Sex
{
    
    
	MALE,
	FEMALE,
	SECRET
};
int main()
{
    
    
	//枚举类型的使用:
	enum Sex sex = SECRET;
	//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异
	sex = 5;//会有类型的差异,比如在cpp条件下就会报错(enum类型 与 int类型不匹配,类型差异)
	return 0;
}

3. Union (community)

Definition : Union is also a special custom type; the variable defined by this type also contains a series of members, and the characteristic is that these members share the same space (so the union is also called a community).
Keywords of union:
union Union members are similar in type to structure members, but have
the characteristics of multiple types of unions :
members of the union share a memory space , so the size of a union variable is at least the size of the largest member ( Because the union must be able to save at least the largest member)

#include <stdio.h>
union Un
{
    
    
	char c;//联合体成员跟结构体成员一样用分号隔开
	int i;
};
int main()
{
    
    
	union Un un;
	printf("%d\n", sizeof(un));//4

	//共用一块地址
	printf("%p\n", &un);//0073F6EC
	printf("%p\n", &(un.c));//0073F6EC
	printf("%p\n", &(un.i));//0073F6EC
	//所以当联合体成员被修改,可能导致其他的成员也跟着相应变化
	//所以在使用联合体成员时,不建议同时操作数据。
	return 0;
}

3.1. Review of big-endian and little-endian judgment - application of union

Little-endian storage : low-address data is stored at a low address, and high-address data is stored at a high address.
Big-endian storage : low-address data is stored at a high address, and high-address data is stored at a low address.
Writing method 1 :

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

Writing method two: Consortium application

#include <stdio.h>
int check_sys()
{
    
    
	union Un//当Un省略就是匿名联合体,此时可以使用,因为这里联合体只需要执行一次与匿名结构体、匿名联合体的性质吻合,只执行一次
	{
    
    
		char c;
		int i;
	}u;
	u.i = 1;
	//因为i和c是联合体变量,所以共用一块内存空间
	//并且当给i赋值给1,以十六进制表示为:0x00 00 00 01
	//所以我们返回c的值,如果c等于0,则高地址数据存放在低地址处,
	//否则c为1,低地址处数据存放在低地址处
	return u.c;
}
int main()
{
    
    
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

3.2. Calculation of the size of the consortium

1. The size of the union is at least the size of the largest member.
2. When the largest 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.

#include <stdio.h>
union Un
{
    
    
	char c[5];//5
	int i;//4
};
int main()
{
    
    
	printf("%zd\n", sizeof(union Un));//8
	return 0;
}
#include <stdio.h>
union Un
{
    
    
	short c[7];//14
	int i;//4
};
int main()
{
    
    
	printf("%zd\n", sizeof(union Un));//16,共用一块地址且是4的倍数,对齐后16
	return 0;
}

Summary :
Common usage scenarios for consortiums are that some members will not use them at the same time.
Using unions can also save space.

4. Conclusion

Once you are familiar with the above content, the use of C language will be more conducive to the readability and efficiency of the program. Please give me your advice if there are any errors in this note.
Half an acre of sugar cubes are opened, and the skylight and cloud shadows linger together.
Ask where the canal can be so clear? Because there is a source of living water. -Zhu Xi (feelings after reading the book)

Guess you like

Origin blog.csdn.net/m0_69455439/article/details/133238210