【C语言】结构体、位段、枚举、以及联合(共用体)的相关原理与使用

本文详细介绍了C语言中的结构体,包括声明、自引用、内存对齐和传参,接着探讨了位段的内存分配和跨平台问题,然后阐述了枚举的定义、优点和使用,最后讨论了联合(共用体)的定义、特点和大小计算。文章强调了内存对齐在结构体大小计算中的重要性,并提醒位段的跨平台问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:C语言学习
🎯长路漫漫浩浩,万事皆有期待

1.结构体

1.1 概述:

C 语言允许用户自己指定这样一种数据结构,它由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体,它相当于其它高级语言中记录。结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

1.2 结构的声明:

以描述 “ 学生 ”为例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//结构体的声明:
struct student
{
   
   
	char name[20];
	int age;
	char sex[5];
	float score;
}s1,s2;
//定义结构体变量s1、s2
//此处定义的结构体变量是全局的
struct student s3, s4;
//定义结构体变量s3、s4
//此处定义的结构体变量等同于声明时定义,也是全局的
int main()
{
   
   
	struct student s5, s6;
	//定义结构体变量s5、s6
	//此处定义的结构体变量是局部的
	return 0;
}

1.3 特殊声明:

关于结构体的不完全声明,即匿名结构体类型

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct
//没有声明结构体标签,即为匿名结构体类型
{
   
   
	char name[20];
	int age;
	char sex[5];
	float score;
}student = {
   
    "Zhang",21,"Man",91.7 };
//匿名结构体类型必须在生声明的同时进行定义
 
int main()
{
   
   
	printf("%s %d %s %.1f\n", student.name, student.age, student.sex, student.score);
	return 0;
}

我们把这种在声明时省略掉结构体标签的结构体称为匿名结构体类型,在使用这种方式进行声明时,由于没有声明结构体标签,导致一旦该结构体结束声明,将无法再次进行定义,所以对于该类型的结构体来说,就必须在声明结构体的同时进行定义(可以不初始化)
再来看下面这个例子:

//结构体类型1:
struct
{
   
   
	char name[20];
	int age;
	char sex[5];
	float score;
}x;
 
//结构体类型2:
struct
{
   
   
	char name[20];
	int age;
	char sex[5];
	float score;
}*p;

在这个示例中,虽然两个结构体类型内的结构体成员完全一样,但因为两者都使用了匿名结构体的声明方式,编译器会把上面的两个声明当成完全不同的两个类型
于是在下面的代码中将被视为非法

p = &x; 
//一种类型的指针指向另一种不同类型,将被视为非法

1.4 结构的自引用:

结构的自引用就是指结构体在自己的声明中引用了自己的一种声明方式。

struct Test
{
   
   
	int data;
	struct Test n;
};
int main()
{
   
   
	struct Test n;
	return 0;
}

我们说这种引用方式是非法的。这是因为,当我们这样进行引用后,在我们定义结构体变量时,会进行自引用,但在自引用中又嵌套了对自身的引用,如此循环往复,而编译器并不知道该在何时停止自引用。

正确的自引用形式:

struct Test
{
   
   
	int data;
	struct Test* NEXT;
    //使用指针指向确定的引用空间
};
int main()
{
   
   
	struct Test n;
	return 0;
}

当我们在进行结构体变量的定义时同样进行了自引用,不同的是这一次我们使用了一个指针,指向了下一个结构体变量的空间,而在这次指向之后,指针指向的空间被固定,不再指向其它空间,如此就实现了真正的结构体自引用。
同时,我们还可以结合关键字 typedef 进行使用:

typedef struct Test
{
   
   
	int data;
	struct <