Detailed explanation of C language custom type - structure struct

structure

Unlike arrays, structures are collections of values ​​called member variables. Each member of the structure can be a variable of different types, while an array is a collection of elements of one type, and a structure is a collection of elements of multiple types.

1. Declaration of structure type

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

struct: keyword of the structure
tag: tag name of the structure
member-list: member variable
variable-list: variable list

Example: define a student type

struct Stu//该结构体类型为 struct Stu类型
{
    
    
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
    float weight;//体重
}s3,s4,s5;//定义了s3,s4,s5三个结构体变量(全局变量)
int main()
{
    
    
    struct Stu s1;
    struct Stu s2;//定义了s1,s2两个结构体变量(局部变量)
}

1. Anonymous structure type

When declaring a structure, it can be declared incompletely, namely: anonymous structure type.

struct 
{
    
    
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
}m,n;
//匿名结构体类型,声明了两个结构体变量:m,n
//该结构体不能再定义结构体变量,用完就没有了

2. Self-reference of structure

error demonstration

struct men
{
    
    
	char name[20];
	int age;
	char sex[5];
	struct men s;//错误的,因为该自引用会无限循环(占用内存无法确定)
};

Demonstrate correctly

struct men
{
    
    
	char name[20];
	int age;
	char sex[5];
	struct men* s;//正确的,因为指针的大小是固定的(4或8个字节)
};
struct Stu
{
    
    
	int age;
	char name[20];
	struct Stu* p;
};
int main()
{
    
    
	struct Stu s1;
	struct Stu s2;
	s1.p = &s1;

	return 0;
}

3. Structure renaming

typedef struct men 
{
    
    
	char name[20];
	int age;
	char sex[5];
}m;
//将结构体重命名为m
int main()
{
    
    
	m x = {
    
     "zzz",18,"sss" };
}
typedef struct 
{
    
    
	char name[20];
	int age;
	char sex[5];
}m;
//将匿名结构体重命名为m
int main()
{
    
    
	m x = {
    
     "zzz",18,"sss" };
}
typedef struct
{
    
    
	char name[20];
	int age;
	char sex[5];
	m* p;//错误的(系统自上而下运行,不能识别m是什么意思
}m; 
int main()
{
    
    
	m x = {
    
     "zzz",18,"sss" };
}

2. Definition and initialization of structure variables

struct Stu1
{
    
    
	int age;
	char name[20];
	float weight;
}s3= {
    
     12,"ass",2.3 };//s3初始化
struct Stu2
{
    
    
	int age;
	char name[20];
    int*p;
	struct Stu1 s;
};

int main()
{
    
    
	struct Stu1 s1 = {
    
     18,"www",142.5 };//s1初始化
	struct Stu2 s2 = {
    
     18,"www",NULL,{
    
    20,"aaa",134.5} };//s2初始化
	printf("%d %s %lf\n", s1.age, s1.name, s1.weight);//打印s1中各项的值
	return 0;
}

3. Structure memory alignment

Introduction: Calculate the size of the following structures

struct S1
{
    
    
	int a;
	char b;
	float c;
};
struct S2
{
    
    
	int a;
	char ch[4];
	float c;
};
struct S3
{
    
    
	int a;
	char b;
	float c;
	double d;
};

int main()
{
    
                                     //结果是:
	printf("%d\n", sizeof(struct S1));// 12
	printf("%d\n", sizeof(struct S2));// 12
	printf("%d\n", sizeof(struct S3));// 24
    //结果并不是单纯的字节相加,因为涉及了结构体的内存对齐
	return 0;
}

1. Alignment rules for structures

  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 size of the structure is an integer multiple of all maximum alignments (including the alignment of the nested structure).

2. Find the offset function offsetof of the structure

Header file #include<stddef.h>
size_t offsetof( structName , _memberName _ ); returns the offset of the structure
offset = member address - structure address
If the structure address is 0, then offset = member address

(1) Example 1 (general structure alignment)

insert image description here

(2) Example 2 (general structure alignment)

Screenshot 2023-03-18 212722.png

(3) Example 3 (Nested structure in structure)

Screenshot 2023-03-18 220325.png

3. Why memory alignment

It can be seen that memory alignment of structures wastes space, so why does memory alignment exist?

  1. Platform reasons (reasons for transplantation):
    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 hardware exceptions will appear.
  2. Performance reasons:
    data structures (especially stacks) should be aligned on natural boundaries as much as possible.
    Because in order to access unaligned memory, the processor needs to make two memory accesses; while aligned memory access requires only one access.

**Overall: The memory alignment of structures is a practice of exchanging space for time. **

4. Write the structure reasonably to save space

When designing the structure, we must not only satisfy the alignment, but also save space. How to do it: Let the members that occupy a small space be gathered together as much as possible. like:

struct s1
{
    
    
	char a;
	int b;
	char c;//一共占12个字节空间
};

struct s2
{
    
    
	char a;
	char c;
	int b;//一共占8个字节空间
}; 

Fourth, modify the default alignment number

For example, the default alignment number in VS is 8, which may not be applicable in some cases. You can use the #pragma preprocessing directive to change the default alignment number.
#pragma pack(num) modify the default alignment number to num
#pragma pack( ) cancel modification

#include<stddef.h>

#pragma pack(1)//修改默认对齐数为1
struct S
{
    
    
	char a;
	int b;
	char c;
};
#pragma pack()//取消修改
int main()
{
    
    
	struct S s = {
    
     0 };
	s.a = 10;
	s.b = 'm';
	s.c = 3.14;
	printf("%d\n", sizeof(struct S));// 未修改为:12
	                                 // 修改后为:6
	return 0;
}

5. Structure parameter passing

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

Use address passing as much as possible : When a function passes parameters, the parameters need to be pushed on 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 on the stack is relatively large, which will lead to a decrease in performance.

6. Bit segment

1. The declaration and structure of the bit field are similar to

Bit field declarations and structures are similar, with two differences:

1. The 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 segment.

struct A
{
    
             //二进制
 int a:2;//  2个bit
 int b:5;//  5个bit
 int c:10;// 10个bit
 int d:30;// 30个bit
};

2. Memory allocation for bit segments

  1. Members of bit fields can be of type int unsigned, int, signed int or char (belonging to the integer family).
  2. The space of the bit field is opened up in the form of 4 bytes (int) or 1 byte (char) according to the need.
  3. Bit segments involve many uncertain factors, bit segments are not cross-platform, and programs that focus on portability should avoid using bit segments.

Screenshot 2023-03-19 174617.png
On the left side of the figure below, it can be seen that the address arrangement is consistent with the arrangement in the figure above
Screenshot 2023-03-19 174543.png

3. The cross-platform problem of bit segment

  1. It is undefined whether an int bit field is treated as signed or unsigned.
  2. The maximum number of bits in a bit field cannot be determined. (16-bit machines can be up to 16, 32-bit machines can be up to 32, written as 27, there will be problems on 16-bit machines)
  3. Whether members of a bit field are allocated from left to right in memory or from right to left is undefined.
  4. When a structure contains two bit fields, and the members of the second bit field are too large to accommodate the remaining bits of the first bit field, it is uncertain whether to discard or utilize the remaining bits.

Therefore : Compared with the structure, the bit field can achieve the same effect, but it can save space very well, but there are cross-platform problems

Guess you like

Origin blog.csdn.net/weixin_74837727/article/details/129653849