Advanced C language - re-recognize the structure

insert image description here
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 a different type.

2 Declaration of structure

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

If we describe a student below, we will think of the student's name, grade, gender, etc., then we can use the structure to create such a variable to contain these contents.

struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	double score;
};

3 Special notices

When declaring a structure, it can be incomplete.

for example

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

These structures can only be used once, because there is no structure tag to form a type, so the anonymous structure can only be used once.
Notice! ! !

The anonymous structure can only be used once, so we cannot perform some operations, such as

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

The compiler will treat them as two completely different types, so p cannot store the address of x

4 Self-referencing of structures

Is it okay to have a member in a struct that is of type the struct itself?

It should be noted here that it does not contain structure variables, but contains structure pointers of this type (it’s a pointer, open your Kazilan’s big eyes to see), you cannot have this type of structure in a structure! ! !
Let's look at an example

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

next is a structure pointer, and the pointer type is struct Node.
error code

struct Node
{
    
    
 int data;
 struct Node;
}

This is the structure of the wrong structure, we are pointers, not variables.

Looking at a code below

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

This is equivalent to redefining an anonymous structure, which is equivalent to a reclusive poet in ancient times who was pulled out by you to fight. Do you think this is reasonable? Although it seems reasonable, it must be a minority, right? !
It is also equivalent to whether the chicken or the egg comes first. Our structure has not been created yet, but there are pointers in it, and there is no type of the structure, so we will rename it, so this must be the wrong correct
code

typedef struct Node
{
    
    
 int data;
 struct Node* next;
}Node;

5 Definition and initialization of structure variables
Declare types and create variables

struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	double score;
}s1,s2;

Create variables s1 and s2 when declaring the structure.
Assign values ​​when initializing

struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	double score;
}s1,s2;
int main()
{
    
    
	struct stu s3 = {
    
     "张三",18,"男",99.9 };
	return 0;
}

Structs contain methods of structs

//初始化:定义变量的同时赋初值。
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 };//结构体嵌套初始化

6 Structural memory alignment
This is the most important content of this chapter. I will explain the method in detail and give an example to illustrate.
First look at the rules
How to calculate?
First, you must master the alignment rules of the structure:

  1. The first member is at 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 = Compiler's default alignment and the smaller value of 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 a structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment, and the
    overall is an integer multiple of all maximum alignments (including the alignment of the nested structure) .

for example

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

insert image description here

Because we start from zero, the char in the structure only occupies one byte, and according to our second rule, the minimum alignment of the integer is 4, so our integer must start with 4 multiples, then we go down four bytes from the position of 4 to the position of 7, and another char type is just right to the position of 8, but our total size must be an integer multiple of the maximum alignment number, here The alignment number is the maximum alignment number of the structure, so it is a multiple of 4, that is 12, just right to the position of 11, so the occupied size is 12.

Let's take a look at the results
insert image description here
, then let's take another example for a deeper understanding

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

insert image description here
insert image description here

In fact, it is the same as the above explanation. It starts from 0 at the beginning, and then double is eight bytes of memory, because it is the same value as our default alignment number, then the alignment number is 8, and one char occupies one word. Section, the minimum alignment of the next int is 4, so we have to start at the position of 12, which is exactly 16 bytes in total, which is also an integer multiple of our maximum alignment double, so the answer is 16.

Let’s talk about the size of a nested structure, I believe everyone will also forget it

struct S3
{
    
    
	double d;
	char c;
	int i;
};

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

insert image description here
insert image description here
So at the position of 31, for example, 0 is just 32, which is a multiple of our maximum alignment number of 8, so the answer is why there is memory alignment at 32
insert image description here
?
We can divide it into two reasons, one is a platform problem, and the other is a performance problem.

  1. Platform reasons (reasons for porting):
    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.
  1. Performance reasons:
    data structures (especially stacks) should be aligned on natural boundaries as much as possible.
    The reason is that to access unaligned memory, the processor needs to make two memory accesses; while aligned memory accesses require only
    one

The memory alignment of the structure is the practice of exchanging space for time.
So how should we design the structure to ensure that it saves both space and memory?
We can design in this way, putting small bytes in front, such as the char type Put the first, followed by the short, which can save space.
For example, the member lists of the following two structures are the same, but their byte sizes are different.

//例如:
struct S1
{
    
    
 char c1;
 int i;
 char c2;
};
struct S2
{
    
    
 char c1;
 char c2;
 int i;
};

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

7 Modify the default alignment

#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;
}

We generally set it to the power of 2, rather than completely irregular like 1 3, for example, on our 32-bit machine platform, we read four bytes at a time, if it is 5, there is no Instead, the regular ones have to be read twice, so the efficiency is not improved.

8 Structure Passing Parameters
When a structure passes parameters, it actually has the same effect as our function passing parameters. When passing parameters, it also opens up space on the stack, and also follows what we often say that a formal parameter is a temporary part of an actual parameter. copy


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;
}

Let's look at the above code, everyone think about whether print1 or print2 is better,
the answer is 2 is better

Explain
that because we pass parameters in the structure, if it is print, it will continue to open up space for storage, which will take up a lot of space, and the space for our print2 is at most 8 on a 64-bit platform, because what we pass is a Address, the address is the size of a pointer variable, that is 4 bytes or 8 bytes, so it is better to pass the address

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, the structure is too large, and the system overhead of pushing the parameters to the stack is relatively large, which will lead to a
decrease in performance.

That's all for today's sharing, see you next time, thank you everyone! ! !

Guess you like

Origin blog.csdn.net/2301_76895050/article/details/132000763