C language (structure, structure alignment)

C language provides us with multiple built-in types, such as int, char, double... Which we often use, but in fact, built-in types can not solve all the complex problems in our life. For example, we need a student type, which includes class, grade, name... This is what a built-in type can do, and the definition of multiple built-in types is too chaotic, which we don't want to see, so the structure came into being.

Structure definition

The structure definition is given below:

struct student  //student is the structure type name
{
	//The following are the built-in types required for the structure
	char name[10];
	int age;
	char _class[12];
	char grade[10];
};//Don't forget the semicolon at the end of the structure

  The structure keyword is struct, followed by the name of the structure type we want to customize, and then define the built-in type we want to integrate in curly braces. At the end of the definition, we add; (easy to forget) you can complete the definition of a structure.

Structure variable definition, initialization and printing

Structure is actually a self-made type defined by us, which is similar to built-in types such as int and char.  

After defining the structure, we also need to create a variable like the built-in type, which is very similar to our built-in type.

int main()
{
	struct student stu1;//C + + Universal
	student stu2;   //Available only in C + +

	return 0;
}

In the main function, we give two methods to define structure variables, but one is only available in C + + syntax, which will directly report errors in. C files (generally, the file suffix used in C language programming is also cpp, so we will explain it directly later using C + + syntax definition).

We can also define variables after the structure. Below, we also directly define the structure variable stu

struct student  //student is the structure type name
{
	//The following are the built-in types required for the structure
	char name[10];
	int age;
	char _class[12];
	char grade[10];
}stu;//Don't forget the semicolon at the end of the structure

Since it is a variable, we can also initialize it, right.

student stu1 = { "caocao", 13, "Class one", "The second day of junior high school"};
student stu2 = { "liubei", 14, "Class one", "Junior three" };
student stu3 = { "sunquan", 17, "Class four", "Senior two"};

For initialization assignment, we only need to assign values to each structure variable in order in the structure definition.

If we do not initialize the structure variable, the default value of each member is random. If more than one member is initialized or curly braces are given, the default value of each element is 0 except the initialized elements

We can also use the member operator '  ’, To access each member of the structure variable.

student stu1 = { "caocao", 13, "Class one", "The second day of junior high school"};
student stu2 = { "liubei", 14, "Class one", "Junior three" };
student stu3 = { "sunquan", 17, "Class four", "Senior two"};

printf("Student 1 sex Name: %s ,Age: %d ,Class: %s ,Grade:%s\n", stu1.name, stu1.age, stu1._class, stu1.grade);
printf("Student 2 sex Name: %s ,Age: %d ,Class: %s ,Grade:%s\n", stu2.name, stu2.age, stu2._class, stu2.grade);
printf("3 student names: %s ,Age: %d ,Class: %s ,Grade:%s\n", stu3.name, stu3.age, stu3._class, stu3.grade);

Structure pointer

  Like other built-in types, structs have corresponding pointer types.

The method is similar to the definition of other built-in pointer types.

student *stu = &stu1;    //C + + syntax only
struct student* _stu = &stu2;   //Both C and C + + are applicable

We can also define after the structure definition  

struct student  //student is the structure type name
{
	//The following are the built-in types required for the structure
	char name[10];
	int age;
	char _class[12];
	char grade[10];
}stu,*Stu;//Don't forget the semicolon at the end of the structure

We can also assign values to built-in types using the same initialization method as built-in types.

With pointers, we can also access a variable through pointers. Here we use the member operator '  ’ And structure pointer operator '- >  ’ There are two ways to access it.

printf("Student 1 Name: %s\n", (*stu).name);
printf("Student 2 Name: %s\n",_stu->name);

In the first way, we de reference the stu pointer to visualize it as a stu1 structure variable, and then access the name through the member operator. Through the pointer operator, we can find it directly through - > structure variable_ The member name of the variable pointed to by stu.

Structure array  

If we need a large number of structural variables of the same type, there is no doubt that it is very inconvenient to define them one by one, and the structure, like the basic built-in type, has the definition form of array to help us solve similar problems.

student StuArr[3] = { { "caocao", 13, "Class one", "The second day of junior high school"} ,
		{ "liubei", 14, "Class one", "Junior three" } ,
		{ "sunquan", 17, "Class four", "Senior two"} };

We assign values to each element of the array (student structure variable), and the data of each structure variable is separated by curly braces. Is it very similar to the form of two-dimensional array?

At the same time, our curly braces can be removed directly.

student StuArr[3] = {  "caocao", 13, "Class one", "The second day of junior high school" ,
 "liubei", 14, "Class one", "Junior three"  ,
 "sunquan", 17, "Class four", "Senior two" };

Like the previous assignment of structure variables, if we do not initialize the structure variables, the default value of each member is random. If more than one member is initialized or curly braces are given, the default value of each element is 0 except the initialized elements.

  Structure alignment

  Now that you know the general knowledge of structures, what do you think is the size of a structure? Add the sizes of all built-in types?

  Huh? However, it seems that this is not the case. If the sizes of all built-in types are added together, it should be 6. Why does it become 8? This involves the knowledge of structure alignment.

Before talking about structure alignment, we need to pay attention to a special case:

Give an empty structure whose size is 1 instead of 0.  

We first need to understand: why do we need structure alignment?

In the above example, if we do not align the structure, we need four bytes to store a, one byte to store b and one byte to store c. It seems to maximize the use of space. In fact, it is very unfriendly to computer reading operations  .

  Assuming this is the way the computer reads data, how does the computer know how many bytes it needs to read? If you know how many bytes you need to read, how do you adjust the size of each read?

The above operations can indeed be realized by the computer, but most of the time will be spent on finding the number of bytes to be read and adjusting the size to be read each time, which will waste a lot of time and reduce the computer work efficiency. This is also what the structure alignment wants to avoid, using space to exchange time.

Let's also look at the memory after structure alignment:

  Suppose the computer reads four bytes at a time:

In this way, the computer can efficiently and quickly complete three reading operations, which takes only two reading times and does not need to spend additional time adjusting the size of each reading.  

Structure alignment rule:

  1. The first address of a structure variable must be an integer multiple of the size of the largest base (built-in) type in the structure variable
  2. The offset of each member in the structure variable relative to the first address of the structure must be an integer multiple of the size of the basic data type of the member
  3. The total size of the structure variable must be an integer multiple of the size of the largest base type in the structure variable

Let's move on to chestnuts:

 

  In this example, we execute the rules of structure alignment from top to bottom.

First, the offset of b from the first address is 1 byte, not an integer multiple of the float size, so we need to adjust it

After adjustment, integer c   The entry of is in full compliance with the structural alignment rules, and the corresponding insertion is directly carried out.

Then d insert, but since the maximum basic type is float and the int size is 4 bytes, the total size of the structure 15 cannot be divided, so it needs to be adjusted

  This completes the alignment.

But,

  If it is allowed to modify the default alignment size (that is, the number of bytes read each time), the rule changes:

  1. The first address of a structure variable must be an integer multiple of min (the size of the largest basic (built-in) type and the size of the default alignment rule) in the structure variable
  2. The offset of each member in the structure variable relative to the first address of the structure must be an integer multiple of the min (basic data type size, default alignment rule size) of the member
  3. The total size of the structure variable must be an integer multiple of min (the size of the largest base type and the size of the default alignment rule) in the structure variable

Default memory alignment size: vs default 8 bytes   gcc default 4 bytes

We can use #pargma pack() in VS to change the default alignment size:
#pragma pack(4) / / modify the default size to 4
#pragma pack() / / restore the default size  

This is equivalent to adjusting the size of the claw (which is very similar to the doll clip) read each time. Our alignment rules also need to be changed according to the size of the claw.

Let's also look at the alignment process:

Everything depends on the size of the claw. It is required that the claw can just catch the variables smaller than him, and catch the variables larger than him several times more. It is very easy to understand after a process.

  Experimental code (for debugging)

#include<stdio.h>

#if 1
struct student  //student is the structure type name
{
	//The following are the built-in types required for the structure
	char name[10];
	int age;
	char _class[12];
	char grade[10];
}stu, * stu;//Don't forget the semicolon at the end of the structure

int main()
{
	//struct student stu1;
	//student stu2;

	//student stu1 = {};
	//Student stu2 = {"Liubei", 14, "class 1", "grade 3"};
	//Student stu3 = {"Sunquan", 17, "class 4", "senior 2"};

	//printf("student 1 Name:% s, age:% d, class:% s, grade:% s\n", stu1.name, stu1.age, stu1._class, stu1.grade);
	//printf("student 2 Name:% s, age:% d, class:% s, grade:% s\n", stu2.name, stu2.age, stu2._class, stu2.grade);
	//printf("student 3 Name:% s, age:% d, class:% s, grade:% s\n", stu3.name, stu3.age, stu3._class, stu3.grade);

	//student *stu = &stu1;    // C + + syntax only
	//struct student* _ stu = &stu2;   // Both C and C + + are applicable

	//printf("student 1 Name:% s\n", (*stu).name);
	//printf("student 2 Name:% s \ n", _stu - > name);

	student StuArr[3] = { { "caocao", 13, "Class one", "The second day of junior high school"} ,
		{ "liubei", 14, "Class one", "Junior three" } ,
		{ "sunquan", 17, "Class four", "Senior two"} };

	student StuArr[3] = {  "caocao", 13, "Class one", "The second day of junior high school" ,
	 "liubei", 14, "Class one", "Junior three"  ,
	 "sunquan", 17, "Class four", "Senior two" };

	//student StuArr[3] = {"caocao"};

	//struct A {
	//	//int a;
	//	//char b;
	//	//char c;
	//};
	//printf("%d", sizeof(A));

#pragma pack(2)
	struct B {
		char a;
		float b;
		int c;
		char d[3];
	};
	printf("%d", sizeof(B));

	return 0;
}

 

 

Tags: C Back-end

Posted on Sun, 05 Dec 2021 16:39:34 -0500 by gdrums