【C语言:自定义类型(结构体、位段、共用体、枚举)】

news2025/1/19 23:16:09

文章目录

  • 1.结构体
    • 1.1什么是结构体
    • 1.2结构体类型声明
    • 1.3结构体变量的定义和初始化
    • 1.4结构体的访问
  • 2.结构体对齐
    • 2.1如何对齐
    • 2.2为什么存在内存对齐?
  • 3.结构体实现位段
    • 3.1什么是位段
    • 3.2位段的内存分配
    • 3.3位段的跨平台问题
    • 3.4位段的应用
    • 3.5位段使用注意事项
  • 4.联合体
    • 4.1联合体的声明
    • 4.2联合体的特点
    • 4.3联合体的大小
    • 4.4联合体与结构体的对比
  • 5.枚举
    • 5.1枚举类型的声明
    • 5.2枚举类型的优点

在这里插入图片描述

1.结构体

1.1什么是结构体

  • C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,
  • 假设我想描述学生,描述⼀本书,这时单⼀的内置类型是不⾏的。描述⼀个学生需要名字、年龄、学号、身高、体重等;描述⼀本书需要作者、出版社、定价等。C语言为了解决这个问题,增加了结构体这种⾃定义的数据类型,让程序员可以⾃⼰创造适合的类型。
  • 结构体是⼀些值的集合,这些值称为成员变量结构体的每个成员可以是不同类型的变量,如:标量、数组、指针,甚⾄是其他结构体

1.2结构体类型声明

关键字:struct

struct stu   //stu 结构体的名字
{
	//以下是结构体的成员变量
	int age;
	char name[20];
	float score;
	//......
};  //分号不能丢

特殊声明方式:匿名结构体,即在声明结构体时不完全声明,省略了结构体的名字。

struct
{
	int a;
	char b;
	float c;
}x;

看下面的代码,这样做的结果时什么?

struct
{
	int a;
	char b;
	float c;
}x;
struct
{
	int a;
	char b;
	float c;
}a[20], * p;

int main()
{
	p = &x;
	return 0;
}

在这里插入图片描述

编译器会把上⾯的两个声明当成完全不同的两个类型,所以是非法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

1.3结构体变量的定义和初始化

  1. 变量的定义
struct Point  
{
	int x;
	int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
  1. 变量的初始化
struct Point p3 = { 10, 20 };
struct Stu //类型声明
{
	char name[15];//名字
	int age; //年龄
};
struct Stu s1 = { "zhangsan", 20 };//按顺序初始化
struct Stu s2 = { .age = 20, .name = "lisi" };//指定顺序初始化
  1. 结构体嵌套、自引用
struct Node
{
	int data;
	struct Point p;//嵌套
	struct Node* next;//自引用
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

1.4结构体的访问

结构体的访问有两种方式:

  • 直接访问:通过点操作符(.)访问
  • 间接访问:通过结构体指针访问,访问方式:结构体指针 -> 成员名

在这里插入图片描述

2.结构体对齐

在下面的代码中,char占1个字节,int占4个字节,那结构体的总大小就是5个字节,真的是这样嘛?

int main()
{
	struct s
	{
		char c;
		int i;
	};
	printf("%d\n", sizeof(struct s));
	return 0;
}

在这里插入图片描述

2.1如何对齐

要弄清结果为什么是8,我们就得了解结构体的对齐规则

  • 1.结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处

  • 2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的⼀个对齐数 与 该成员变量大小的较小值

  • 3.VS 中默认的值为 8

  • 4.Linux中 gcc 没有默认对齐数,对齐数就是成员自身的大小。

  • 5.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处

  • 6.结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍

#pragma这个预处理指令,可以修改编译器的默认对齐数

#pragma pack(1)//设置默认对⻬数为1
struct S
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认

到底是怎么对齐的呢?看下图
在这里插入图片描述

来练习几个吧

在这里插入图片描述

2.2为什么存在内存对齐?

大部分的参考资料都是这样说的:

  1. 平台原因 (移植原因):
    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:
    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对⻬是拿空间来换取时间的做法。
因此,设计结构体的时候,我们既要满足对齐,⼜要节省空间,就要让占用空间小的成员尽量集中在⼀起。

3.结构体实现位段

3.1什么是位段

你听说过位段吗?是不是只听说过段位呀哈哈

位段的声明和结构是类似的,有两个不同:

  1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以 选择其他类型,例如char。
  2. 位段的成员名后边有⼀个冒号和⼀个数字

位段的位其实指的就是二进制位,下面的A就是位段类型的

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n", sizeof(struct A));
	return 0;
}

2+5+10+30=47bit,一个字节是8个bit,那是不是6个字节就够了呢?
在这里插入图片描述
结果是8个字节。为什么是8个字节呢?----那是因为位段也存在对齐,位段的总大小也要对齐到自己最大成员变量的整数被。
注意:位段后的数字不可大于该数字本身的大小,否则就报错

3.2位段的内存分配

关于位段在内存中是如何存储的,C语言标准并未给出定义,下面我们就研究以下在VS中,位段是如何存储的。

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

我们假设如果第一个字节中放不下了,就放在下一个字节中,第一个字节中剩余的比特位就舍弃,那么就是下面的结果:
在这里插入图片描述
vs中是不是这样存储的呢?看图我们知道,确实就是这样存的。
在这里插入图片描述

3.3位段的跨平台问题

  1. int 位段被当成有符号数还是⽆符号数是不确定的。
  2. 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

因此:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

3.4位段的应用

下图是网络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥使⽤位段,能够实现想要的效果,也节省了空间,这样⽹络传输的数据报大小也会较小⼀些,对网络的畅通是有帮助的。
在这里插入图片描述

3.5位段使用注意事项

  • 位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的
  • 所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊放在⼀个变量中,然后赋值给位段的成员。

在这里插入图片描述

4.联合体

4.1联合体的声明

  • 像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以是不同的类型。
  • 但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体。
  • 给联合体其中⼀个成员赋值,其他成员的值也跟着变化。

在这里插入图片描述

4.2联合体的特点

  1. 所有变量公用同一块空间
  2. 改变一个成员,其它成员跟着变

在这里插入图片描述

4.3联合体的大小

  • 联合的大小⾄少是最⼤成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对⻬数的整数倍

在这里插入图片描述

4.4联合体与结构体的对比

在这里插入图片描述
因此,使用联合体是比较节省空间的。

5.枚举

5.1枚举类型的声明

枚举枚举,顾名思义,就是一一列举。在生活中可以一 一列举出来的就可以使用枚举类型。例如

⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
⽉份有12个⽉,也可以⼀⼀列举

枚举的关键字是enum,枚举成员用逗号隔开,最后一个成员不加逗号
在这里插入图片描述

  • 枚举的可能取值是常量,不能修改,因此我们也叫做枚举常量
  • 枚举类型的变量的值只能是枚举的可能取值

在这里插入图片描述

enum day
{
	Monday,		
	Tuesday,	
	Wednsdsday = 10,	
	Thursday,	
	Friday,		
	Saturday = 20,	
	Sunday		
};

enum day d = Sunday;//使⽤枚举常量给枚举变量赋值

5.2枚举类型的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 便于调试,预处理阶段会删除 #define 定义的符号
  4. 使用⽅便,⼀次可以定义多个常量
  5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1286842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全国规模最大!玻色量子加入算力并网行动!

8月19日,在2023中国算力大会主论坛上,中国移动携手多个超算中心、智算中心,以及云服务商,共同发起全国规模最大的“百川”算力并网行动,打造算力类型最全、规模最大、覆盖最广的“百川”算力并网平台,加快推…

提高Idea编码速度和插件自用推荐

非常推荐 Easy Javadoc 一款注释生成器,很好使~免费,配合使用腾讯、百度之类的翻译免费额度完全够用了,印象中是50万字符每月。下图是使用快捷键生成的注释(我采用鼠标侧面按键,随手一按很方便) Chinese …

HTTP会话技术---Cookie、Session和Token介绍及它们在JavaWeb中的使用

当涉及到Web应用程序的身份验证和状态管理时,我们通常会使用到Cookie、Session和Token这些会话技术。下面是对它们的介绍,并在JavaWeb中的示例 Cookie(HTTP Cookie) Cookie是一种存储在用户浏览器中的小型文本文件,由…

360公司-2019校招笔试-Windows开发工程师客观题合集解析

360公司-2019校招笔试-Windows开发工程师客观题合集 API无法实现进程间数据的相互传递是PostMessage2.以下代码执行后,it的数据为(异常) std::list<int> temp; std::list<int>::iterator it = temp.begin(); it = --it; 3.API在失败时的返回值跟其他不一样是 …

OSPF浅析

一、预习&#xff1a; 1、优点&#xff1a; 是一种典型的链路状态路由协议&#xff0c;协议号89&#xff0c;把大型网络分隔为多个较小、可管理的单元&#xff1a;Area a.减少LSA泛洪范围&#xff0c;有效地把拓朴变化 控制在区域内&#xff0c;达到网络优化的目的…

混音编曲软件tudio One 6.5.1 保姆级安装教程

根据软件大数据显示De-Esser驯服人声嘶嘶声和其他高频声音&#xff0c;和其他 Studio One 中新的去实体插件一样高效且直观易用&#xff0c;使用“收听”按钮查找有问题的频率&#xff0c;然后使用相关的旋钮和 S-Mon 功能拨入 S-Reduce 量即可。实际上我们可以这样讲工作流和协…

消费数据可视化大屏,助力金融机构智慧运维

在今天的数字化时代&#xff0c;消费数据的可视化已经成为了一种重要的趋势。通过将消费数据以图表、图像等形式展现出来&#xff0c;可以帮助我们更直观地了解消费者的行为和趋势。同时&#xff0c;这也为企业提供了更多的分析和决策依据。无论是针对市场营销策略的制定&#…

如何搭建eureka-server

在Spring Cloud项目的pom文件中添加eureka-server的starter依赖坐标 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://ma…

科技论文中的Assumption、Remark、Property、Lemma、Theorem、Proof含义

一、背景 学控制、数学、自动化专业的学生在阅读论文时&#xff0c;经常会看到Assumption、Remark、Property、Lemma、Theorem、Proof等单词&#xff0c;对于初学者可能不太清楚他们之间的区别&#xff0c;因此这里做一下详细的说明。 以机器人领域的论文为例。 论文题目&…

Footprint Analytics x Future3 万字研报:AI 与 Web3 数据行业融合的现状、竞争格局与未来机遇探析(上)

GPT的横空出世将全球的目光吸引至大语言模型&#xff0c;各行各业都尝试着利用这个“黑科技”提高工作效率&#xff0c;加速行业发展。Future3 Campus携手Footprint Analytics共同深入研究AI与Web3结合的无限可能&#xff0c;联合发布了《AI与Web3数据行业融合现状、竞争格局与…

数电笔记之寄存器

数电 1 数字电路基础 1.2 二进制数据表达 1.2.1 二进制简介 1.2.2 用二进制表达文字 常用的中文字符集&#xff1a;GBK&#xff0c;UTF8 1.2.3 用二进制表达图片 图片像素化&#xff0c;像素数字化 1.2.4 用二进制表达声音 1.2.5 用二进制表达视频 1.3 数字电路 1.3…

tmux简单使用

它允许你在一个终端窗口中创建多个终端会话&#xff0c;并在它们之间进行切换。以下是tmux的一些主要用途和功能&#xff1a; 多窗口&#xff1a; Tmux允许你在一个终端中创建多个窗口。每个窗口可以包含一个或多个终端会话&#xff0c;你可以轻松地在这些窗口之间切换。面板分…

1-4节电池升降压充电IC解决方案

描述 MP2760是一款集成窄电压DC&#xff08;NVDC&#xff09;电源路径管理功能和USB On-the-Go(OTG)功能的升降压充电IC&#xff0c;兼容USB PD&#xff0c;适用于单节至4节串联的电池包应用。该芯片的充电输入电压范围广&#xff0c;可支持最高22V。 当启用电池放电模式&…

HITOS_LAB5 进程运行轨迹的跟踪与统计

5. 进程运行轨迹的跟踪与统计 5.1. 实验目的 掌握 Linux 下的多进程编程技术&#xff1b;通过对进程运行轨迹的跟踪来形象化进程的概念&#xff1b;在进程运行轨迹跟踪的基础上进行相应的数据统计&#xff0c;从而能对进程调度算法进行实际的量化评价&#xff0c; 更进一步加…

基于Transformer的U型医学图像分割网络综述

基于Transformer的U型医学图像分割网络综述 论文来自 计算机应用 2023 摘 要&#xff1a;目前&#xff0c;医学图像分割模型广泛采用基于全卷积网络&#xff08;FCN&#xff09;的U型网络&#xff08;U-Net&#xff09;作为骨干网&#xff0c;但卷积神经网络&#xff08;CNN&am…

十三、FreeRTOS之FreeRTOS时间管理

本节主要介绍以下内容&#xff1a; 1&#xff0c;延时函数介绍&#xff08;了解&#xff09; 2&#xff0c;延时函数解析&#xff08;熟悉&#xff09; 3&#xff0c;延时函数演示实验&#xff08;掌握&#xff09; 4&#xff0c;课堂总结&#xff08;掌握&#xff09; 一、…

【Transformer论文精读系列】(一)如何理解Transformer里的注意力机制?

论文&#xff1a;Attention Is All You Need 参考李沐老师的讲解视频&#xff1a; Transformer论文逐段精读【论文精读】_哔哩哔哩_bilibili 其他参考&#xff1a; 超强动画&#xff0c;一步一步深入浅出解释Transformer原理&#xff01;_哔哩哔哩_bilibili Transformer论文逐段…

2023年【A特种设备相关管理(锅炉压力容器压力管道)】考试内容及A特种设备相关管理(锅炉压力容器压力管道)复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 A特种设备相关管理&#xff08;锅炉压力容器压力管道&#xff09;考试内容根据新A特种设备相关管理&#xff08;锅炉压力容器压力管道&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将A特种设备相关管理…

1970-2022年中国省级国家级开发区数据集

1970-2022年Z国省级国家级开发区数据集 1、时间&#xff1a;1970-2022年 2、指标&#xff1a;单位名称、所属区域、所属省份、所属级别、开发区类型、关注热度、成立时间、核准面积、主导产业、地址、联系电话、经纬度 3、范围&#xff1a;2781个开发区 4、来源&#xff1a…

机器学习---朴素贝叶斯分类器的实现(对文本进行侮辱性言论和非侮辱性言论的分类)

1. loadDataSet函数 import numpy as np# 构造loadDataSet函数用于生成实验样本 def loadDataSet(): postingList[[my, dog, has, flea, problems, help, please],[maybe, not, take, him, to, dog, park, stupid],[my, dalmation, is, so, cute, I, love, him],[stop, postin…