stay C In language , In addition to the basic data types we often use , There is also a type called custom type . such as : We want to describe a student . The student has a name , Gender , Age , Height, etc . Basic data types alone cannot be fully described . At this time, we need to use our custom types for description . Custom types include structures , Enumeration and Consortium .

one , structural morphology

Structure is a collection of values , These values are called member variables , Each member variable can have different types .

1, statement

struct tag// there tag Represents the label , Not a variable name

{

        member-list;// Member variable

}variable-list;// Variable list , Used to define variables . Notice the semicolon here

such as , Describe a person :
struct person { char name[20]; char sex[5]; int age; char nation[20]; };
The list of variables here can be empty . The variables defined in the variable list are global variables .

2, Define and initialize

To define , It can be directly in the variable list , You can also main Defined in function .
struct person { char name[20]; char sex[5]; int age; char nation[20];
}person1;// Structure variable person1 struct person person2;// Structure variable person2 int main(void) {
struct person person3;// Structure variable person3 struct person
person4[2];// Structure array variable person4, There are two elements , All structural types return 0; }
Initialization is also simple .
#include<stdio.h> struct person { char name[20]; int age; }person1 =
{"zhangsan", 18};// Structure variable person1 struct person person2 = {"lisi",
18};// Structure variable person2 int main(void) { struct person person3 = {"wangwu",
18};// Structure variable person3 struct person person4[2] = {"abc", 18, {"def",
18}};// Add or not {} Fine return 0; }
sometimes , Nested structures can also occur :
struct person { char name[20]; int age; }person1 = {"zhangsan",
18};// Structure variable person1 struct people { struct person person; char nation[20]; };
  Initialize it :

struct people people = { {"zhangsan",18}, "XXX" };// Initialization of nested structures

When we declare a structure , It can also be incomplete , Omit the label at this time .
struct { int a; char b; float c; }a;
In one case, the label cannot be omitted , Immediate use typedef Keyword time .typedef Keyword can define a new name for a data type . If omitted , Will report an error .
typedef struct S { int data[1000]; int num; }s; s s1 = { {1,2,3,4}, 1000 };
3, Access to structure members

The access of structure members needs to pass through points (.) Operator to access . Let's print these initialized variables .
#include<stdio.h> struct person { char name[20]; int age; }person1 =
{"zhangsan", 18};// Structure variable person1 struct people { struct person person; char
nation[20]; }; struct person person2 = {"lisi", 18};// Structure variable person2 int
main(void) { struct person person3 = { "wangwu", 18 };// Structure variable person3 struct
person person4[2] = {"abc", 18, {"def", 18}};// Add or not {} Fine struct people people =
{ {"zhangsan",18}, "XXX" };// Initialization of nested structures printf("%s\n", person1.name);
printf("%d\n", person1.age); printf("--------------\n"); printf("%s\n",
person2.name); printf("%d\n", person2.age); printf("--------------\n");
printf("%s\n", person3.name); printf("%d\n", person3.age);
printf("--------------\n"); printf("%s\n", person3.name); printf("%d\n",
person3.age); printf("--------------\n"); printf("%s\n", person4[1].name);
printf("%d\n", person4[1].age); printf("--------------\n"); printf("%s\n",
people.person.name); printf("%s\n", people.nation); return 0; }

  Now? , Let's take a look at the members of the variable that the struct pointer accesses . There are the following codes :
struct Stu { char name[20]; int age; }; void print(struct Stu* ps) {
printf("name = %s age = %d\n", (*ps).name, (*ps).age);
// Use structure pointers to access members that point to objects , To simplify , use -> Operator to replace (*). operation . printf("name = %s age = %d\n",
ps->name, ps->age); } int main() { struct Stu s = { "zhangsan", 20 };
print(&s);// Structure address transmission parameter return 0; }

#include<stdio.h> struct person { char name[20]; int age; }; struct people {
struct person* person; char nation[20]; }; int main(void) { struct person
person = { "zhangsan", 18 }; struct people people = { &person ,"XXX"};
printf("%s\n", people.person->name); printf("%d\n", people.person->age);
printf("%s\n", people.nation); return 0; }

 4, Structural transmission parameters
struct S { int data[1000]; int num; }; struct S s = { {1,2,3,4}, 1000 };
// Structural transmission parameters void print1(struct S s) { printf("%d\n", s.num); } // Structure address transmission parameter void
print2(struct S* ps) { printf("%d\n", ps->num); } int main() { print1(s);
// Transmission structure print2(&s); // Transmission address return 0; }

When passing parameters , Parameter stack required . When passing a structure object , Because the structure is too large , The system overhead of parameter stack pressing is relatively large , Resulting in performance degradation . in addition , When calculating the size of the structure , If it is the value of the passed structure , It will cause the size of the structure to increase infinitely . therefore , The structure needs to pass the address when passing the parameter .

5, Structure memory alignment

Now? , Let's discuss the memory size of the structure .

5.1, Take a look at the following code , Calculate its size (*):
struct S1 { char c1; int i; char c2; }; int main(void) { printf("%d\n",
sizeof(struct S1)); return 0; }

  We found , The size of this structure is not what we think 6 Bytes , But 12 Bytes .

The structure memory is calculated as follows :

1, The first member is offset from the structure variable by 0 Address of .

2, Other member variables should be aligned to the address of an integer multiple of the alignment tree . Alignment number = Compiler default alignment number And The smaller value of the member size . VS The default value in is 8, Some default to 4.

3. The total size of the structure is the maximum number of alignments ( Each member variable has an alignment number ) Integer multiple of .

4. If a structure is nested , The nested structure is aligned to an integer multiple of its maximum number of alignments , Integral of structure Body size is the maximum number of all alignments ( Number of alignments with nested structures ) Integer multiple of .

In short , namely : In memory , The first variable is placed at the beginning 0 Address Office , Where should I put the others , It depends on the alignment number . The number of alignments is the minimum of the default number of alignments and member size . After the alignment number is put , The size of this structure is an integral multiple of the maximum number of alignments .

Calculate the size of the following nested structure : 
struct S1 { char c1;//1 int i;//4 };// Size 8 struct S2 { char c1;//1 struct S1
s1;//8 int d;//4 }; int main(void) { printf("%d\n", sizeof(struct S2)); return
0; }

  When calculating , You cannot add up the size of member variables directly , At the multiple of the maximum value of the alignment number . For example, the first calculation (*) place : Add up to 6, Fetching aligned data (4) Integer multiple of , The result is 8, This is obviously inconsistent with the calculated results .

I'm looking at the last one :
struct S { short s1;//2 char c1;//1 int s2;//4 }; int main(void) {
printf("%d\n", sizeof(struct S)); return 0; }

  If you do it skillfully , There is no need to draw a picture , Just do the calculation directly . Sometimes it happens short and char Together , At this time , Can be directly regarded as 4 Size .

5.2, Reasons for memory alignment :

1. Platform reason ( Reasons for transplantation ): Not all hardware platforms can access any data at any address ; Some hardware platforms can only take some special data at some addresses Type specific data , Otherwise, a hardware exception is thrown .

2. Performance reasons : data structure ( Especially stack ) It should be aligned on natural boundaries as much as possible .
The reason is , To access misaligned memory , The processor needs to make two memory accesses ; Alignment requires only one access to memory .

on the whole : The memory alignment of structures is a method of trading space for time . This practice is very common .

When we design the structure , To meet both alignment , And save space , Then let the members who occupy less space gather together as much as possible . If we will (*) Change the order of , Like two char Type together , The size of this structure will change .

5.3, Modify the default number of alignments
#pragma pack(1)// Set the default number of alignments to 1 struct S2 { char c3; int i2; char c4; }; int main()
{ printf("%d\n", sizeof(struct S2));//6 return 0; }
Restore to default :

#pragma pack()// Unset the default number of alignments , Restore to default  

two , Bit segment

1, Definitions and declarations

The structure can implement bit segments . The declaration of a bit segment is similar to that of a struct . A bit segment defines a structure in bits ( Or consortium ) Space occupied by member variables in . Using bit segment structure can save space , And easy to operate .  Such as bit segment A:
struct A { int _a:2; int _b:5; int _c:10; int _d:30; };
The member name of the bit field is followed by a colon and a number . The following numbers are in bits . The member of a bit segment must be an integer family .

2, Memory allocation of bit segments

The space of bit segments is as needed 4 Bytes ( int ) perhaps 1 Bytes ( char
) The way to open up . Preceding bit segment A species ,_a yes int type , So 4 Bytes . that A What is the size of the (32 position )?
struct A { int _a : 2; int _b : 5; int _c : 10; int _d : 30; }; int main() {
// What is the result of the output ? printf("%d\n", sizeof(struct A)); return 0; }

  How is this calculated ?

here ,_a Opened up 4 Size of bytes , however _a Just two bits are enough . stay 32 Lower position , also 30 Bits ._b need 5 Bits , Remaining 25 Bit ,_c need 10 Bits , That's all that's left 15 Bits ,_d need 30 Bits , The rest 15 Not enough bits , Just opening up 4 A space of bytes _b. The graph here assumes that it is placed from the left .

Let's look at this problem ( stay VS The top is from the right ):
struct S { char a : 2; char b : 3; char c : 4; char d : 5; }; int main(void) {
struct S s = { 0 }; s.a = 10; s.b = 12; s.c = 3; s.d = 4;// What is it like in memory return 0; }

3, Cross platform problem of bit segment

1. int Whether a bit segment is treated as a signed number or an unsigned number is uncertain .

2. The number of the largest bits in the bit segment cannot be determined .(16 Bit machine Max 16,32 Bit machine Max 32, finish writing sth. 27, stay 16 Bit machine There will be problems with the actuator .

3. The members in the bit segment are allocated from left to right in memory , Right to left allocation criteria are not defined .

4. When a structure contains two bit segments , The member of the second bit segment is relatively large , When the remaining bits of the first bit segment cannot be accommodated , Discard the remaining bits or use them , This is uncertain .

Compared with structure , Bit segments can achieve the same effect , But it can save space , However, there are cross platform problems .

three , enumeration

enumeration , Is to list them one by one . List the possible values one by one .

1, definition :
enum Day// week { Mon, Tues, Wed, Thur, Fri, Sat, Sun }; enum Day// week { Mon,
Tues, Wed, Thur, Fri, Sat, Sun }; int main(void) { printf("%d\n", Mon);
printf("%d\n", Tues); printf("%d\n", Wed); printf("%d\n", Thur); printf("%d\n",
Fri); printf("%d\n", Sat); printf("%d\n", Sun); return 0; }

  As defined above enum Day Is an enumeration type .{} The contents in are possible values of enumeration types , Also called enumeration constant
. These possible values are valuable , Default from 0 start , One time increment 1, Of course, initial values can also be assigned when defining .
enum Day// week { Mon, Tues, Wed, Thur = 6, Fri, Sat, Sun };

2, advantage

1. Increase the readability and maintainability of the code

2. and #define The defined identifier comparison enumeration has type checking , More rigorous .

3. Prevent naming pollution ( encapsulation )

4. Easy to debug

5. Easy to use , You can define more than one constant at a time

3, use

stay switc In the statement , If we have too many branches ,case The label at the back is a number , At this time , You need to know what this number stands for , You need to find it . But if we use enum, You can replace the number with a constant name that can be known at a glance , Greatly improve the readability of the code .
enum Game { EXIT, GAME_BEGIN, GAME_DISCONTINUE }; int main(void) { switch (1)
{ case GAME_BEGIN: printf(" You started the game !\n"); case GAME_DISCONTINUE:
printf(" You stop the game !\n"); case EXIT: printf(" You quit the game !\n"); } return 0; }
  four , Consortium ( Common body )

1, definition :

Consortium is also a special custom type , Variables defined by this type contain a series of members . These members share a common space , So it is also called common body . The definition of consortium is similar to that of structure .
// Type of joint declaration union Un { char c; int i; }; // Definition of joint variables union Un un;
2, characteristic :

The consortium shares a space , such , The size of this joint variable , At least the size of the largest member , To store the largest member .
#include<stdio.h> union Un { int i; char c; }; union Un un; int main(void) {
// Are the output results the same ? printf("%p\n", &(un.i)); printf("%p\n", &(un.c));
// What are the output results below ? un.i = 0x44; un.c = 0x55; printf("%x\n", un.i); return 0; }

 

From here, we can see the characteristics of the consortium : Share a space . just because of this , So I'm printing un.i When , You will find that the result is 0x55. there 0x44 Covered . Characteristics of the Consortium , It can be used to judge the size of the current computer .
union Un { int i; char ch; }; int main(void) { union Un un; un.i = 1;
printf("%d\n", un.ch);//1, It's a small end return 0; }
3, Calculation of consortium 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 , You need to align to an integer multiple of the maximum number of alignments .
union Un1 { char c[5];// common 5 Elements , Each account 1 Bytes , The total size is 5 int i;//4 }; int main(void) {
printf("%d\n", sizeof(union Un1));//8, Is the maximum number of alignments 4 Multiple of . Note not 5, there 5 Is the total size of the array return 0; }
union Un2 { short c[7];//2*7 int i;//4 }; int main(void) { printf("%d\n",
sizeof(union Un2));//16 return 0; }

Technology