[C language] Custom types: structure, enumeration, union

Table of contents

1. Structure

        1. Declaration of structure type

        2. Self-reference of structure

        3. Definition and initialization of structure variables

        4. Structure memory alignment

        5. Structure parameter passing

        6. Structure implements bit segments (filling of bit segments & portability)

2. Enumeration

        1. Definition of enumeration type

        2. Advantages of enumeration

        3. Use of enumerations

Three, union

        1. Definition of union type

        2. Characteristics of union

        3. Calculation of joint size

4. Summary


1. Structure

        1. Declaration of structure type

        1.1 Basic knowledge of structure

A structure is a collection of values ​​called member variables. Each member of the structure can be a variable of different types.

         1.2 Declaration of structure

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

        For example, describe a student :

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

        1.3 Special Statement

        When declaring a structure, you can declare it incompletely

        for example:

//匿名结构体类型
struct
{
    int a;
    char b;
    float c;
}x;

struct
{
    int a;
    char b;
    float c;
}a[20], *p;

        The above two structures omitted the structure tag when declaring it.

        So here’s the problem?

//Based on the above code, is the following code legal? p = &x;        

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

        2. Self-reference of structure

        Is it okay to include a member in a structure that is of type the structure itself?

//代码1
struct Node
{
    int data;
    struct Node next;
}; //可行否?

如果可以,那sizeof(struct Node)是多少?

        The answer is that it will perform an infinite loop. This way of writing is wrong!

        Correct way to self-reference:

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

        Using pointers can self-reference without causing an infinite loop, because the space size of the pointer is a fixed number.

//代码3
typedef struct
{
    int data;
    Node* next;
}Node;
//这样写代码,可行否?

//解决方案:
typedef struct Node
{
    int data;
    Node* next;
}Node;

        3. Definition and initialization of structure variables

        With the structure type, 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}; //结构体嵌套初始化

        4. Structure memory alignment

        We have mastered the basic use of structures

        Now let’s discuss a problem in depth: calculating the size of a structure

        This is also a particularly popular test point: structure memory alignment

        Here are some practice examples :

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

         Structure nesting problem:

#include<stdio.h>
struct S3
{
	double d;
	char c;
	int i;
};
int main()
{
	struct S4
	{
		char c1;
		struct S3 s3;
		double d;
	};
	printf("%d\n", sizeof(struct S4));
}

 Test points

How to calculate?

First, you must master the alignment rules of structures:

        1. The first member is at the address offset 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 of the compiler's default alignment number and the size of the member. The default value in VS is 8. There is no default alignment number in Linux. The alignment number is the size of the member itself.

        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 a structure is nested and the nested structure is aligned to an integer multiple of its own maximum alignment number, the overall size of the structure is an integer of all maximum alignment numbers (including the alignment number of nested structures) times.

        Why does memory alignment exist?

        Most of the reference materials say this:

        1. Platform reasons (transplantation 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 whenever possible. The reason is that in order to access unaligned memory, the processor needs to make two memory accesses; aligned memory access requires only one access.

        In general:

        Memory alignment of structures trades space for time.

        When designing a structure, we must not only satisfy alignment but also save space. How to do this:

        Keep members who take up less space together as much as possible.

#include<stdio.h>
int main()
{
	//例如:
	struct S1
	{
		char c1;
		int i;
		char c2;
	}s1;
	struct S2
	{
		char c1;
		char c2;
		int i;
	}s2;
	printf("%d\n%d", sizeof(s1), sizeof(s2));
}

 The members of type S1 and S2 are exactly the same, but there are some differences in the size of the space occupied by S1 and S2.

        Modify the default alignment number

We have seen the #pragma preprocessing directive before. Here we use it again to change our default alignment number.

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

         When the alignment of the structure is inappropriate, we can change the default alignment number ourselves.

        5. Structure parameter passing

       Direct code demonstration:

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 print1 and print2 functions above is better?

        The answer is: print2 function is preferred

       reason:

        When a function passes parameters, the parameters need to be pushed onto the stack, which will cause system overhead in time and space.

        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, which will lead to performance degradation.

        6. Structure implementation bit segment

        6.1 What is a bit segment?

        The declaration and structure of bit fields are similar, with two differences:

1. 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:

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

         6.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 allocated in the form of 4 bytes (int) or 1 byte (char) according to the needs.

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

         6.3, cross-platform issues in bit segments

1. It is uncertain 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 number for a 16-bit machine is 16, and the maximum number for a 32-bit machine is 32. If written as 27, problems may occur on a 16-bit machine.

3. Whether members in a bit segment are allocated from left to right or right to left in memory has not yet been defined.

4. When a structure contains two bit fields, and the members of the second bit field are larger and cannot accommodate the remaining bits of the first bit field, it is uncertain whether to discard the remaining bits or use them.

Summarize:

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

          

2. Enumeration

        1. Definition of enumeration type

        Enumeration, as the name suggests, is to enumerate 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, which 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.

        You can use enumerations here!

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 valuable, starting from 0 by default and increasing by 1 in sequence. Of course, an initial value can also be assigned when declaring the enumeration type. For example:

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

        2. Advantages of enumeration

        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. Easy to debug

4. Easy to use, multiple constants can be defined at one time

        3. Use of enumerations

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

        clr=5 will cause an error because the data types are different!

Three, union

        1. Definition of union type

Union is also a special custom type

Variables defined in this type also contain a series of members. The characteristic is that these members share the same space (so a union is also called a union). for example:

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

There are also some use cases, such as determining the big and small endian storage of the current computer.

#include<stdio.h>
//联合类型的声明
union Un
{
	char c;
	int i;
};
//联合变量的定义
int main()
{
	union Un un;
	un.i = 1;
	//计算连个变量的大小
	if (un.c == 1)
	{
		printf("小端存储");
	}
	else printf("大端存储");
	return 0;
}

        3. 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 maximum alignment number, it must be aligned to an integer multiple of the maximum alignment number.

       for example:

#include<stdio.h>
int main()
{
	union Un1
	{
		char c[5];
		int i;
	};
	union Un2
	{
		short c[7];
		int i;
	};
	//下面输出的结果是什么?
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

4. Summary

       This chapter has a lot of knowledge and comprehensive coverage. It is very suitable for in-depth exploration. It is a very good choice as a review study material!

Guess you like

Origin blog.csdn.net/m0_71676870/article/details/131764033