C语言自定义类型详解(保姆级教学)

news2024/11/26 0:43:16

目录

1.结构体

1.1结构体的介绍

1.2结构体的声明

1.3特殊声明(匿名结构体类型)

1.4结构体自引用

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

1.6结构体内存对齐

1.7修改默认对其数

2.位段

2.1什么是位段

2.2位段的内存分配

3.枚举

3.1枚举的定义

3.2枚举的优点

4.联合体(共用体)

4.1联合体类型的定义

4.2联合体的特点

 4.3联合体大小的计算


什么是自定义类型?

在C语言中,我们可以使用结构体(Struct),枚举(Enum),联合体(Union)来创建自定义的类型。

1.结构体

1.1结构体的介绍

结构体(Struct):结构体是一种用户定义的数据类型,用于将不同类型的数据组合在一起,形成一个新的复合类型。结构体由一组成员(member)组成,每个成员可以是不同的数据类型,如整型、字符型、浮点型、指针等。结构体的定义使用 struct 关键字,然后指定结构体的名称以及成员列表。

1.2结构体的声明

struct student
{
	char name[20];
	int age;
	char sex[5];
	char id[20]
};

在上述代码中,我们定义了一个名为student的结构体,包含了一个整形类型和三个字符类型的数组。

1.3特殊声明(匿名结构体类型)

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

在上述代码中,省略了结构体的标签——这就是匿名结构体类型。

1.4结构体自引用

我们可以在结构体中包含一个结构体,如果包含的这个结构体是该结构体本身的结构体指针即为结构体的自引用。

struct student
{
	int age;
	char name[20];
	struct student* s1;
};

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

struct student
{
	int age;
	char name[20];
}s1,s2;//在声明结构体类型时定义变量s1,s2

struct student s3;//定义结构体变量s3


struct point
{
	int x;
	int y;
}p1={1,1};//结构体嵌套初始化


struct point p2 = { 1,2 };//初始化

1.6结构体内存对齐

结构体内存对齐是用来计算结构体的大小的

如何计算?

首先得掌握结构体的对齐规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
Linux中没有默认对齐数,对齐数就是成员自身的大小
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

实例:

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

 

为什么存在内存对齐?
大部分的参考资料都是如是说的:
1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。

总体来说:
结构体的内存对齐是拿空间来换取时间的做法

1.7修改默认对其数

#pragma pack(1)//设置默认对齐数为1
struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
#pragma pack ()//取消设置默认对齐数,还原为默认

2.位段

2.1什么是位段

位段(Bitfields)是C语言中一种用于定义结构体成员的技术,它允许我们对结构体中的数据进行位级别的控制。

位段的目的是在结构体成员中存储各个字段(或位)的数据,并利用较少的内存空间。通常,在处理一些较小范围的整数值时,使用完整的字节或更大的数据类型可能会浪费内存。

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

1.位段的成员必须是 int、unsigned int 或signed int 。
2.位段的成员名后边有一个冒号和一个数字

比如:

struct student
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

student就是一个位段类型。那student的大小呢?

2.2位段的内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

实例:

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

3.枚举

3.1枚举的定义

enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜色
{
RED,
GREEN,
BLUE
};

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫 枚举常量 。
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。
例如:

enum Color//颜色
{
RED=1,
GREEN=2,
BLUE=4
};

3.2枚举的优点

为什么使用枚举?
我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 便于调试
4. 使用方便,一次可以定义多个常量

4.联合体(共用体)

联合体是一种特殊的数据类型,允许在相同的内存位置存储不同类型的数据。与结构体不同的是,联合体中的各个成员共享相同的内存空间。

4.1联合体类型的定义

//联合体类型的声明
union Un
{
	char c;
	int i;
};

int main()
{
	//联合体变量的定义
	union Un un;
	//计算联合体变量的大小
	printf("%d\n", sizeof(un));
	//打印结果为4
}

4.2联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联
合至少得有能力保存最大的那个成员)。

union Un

{
	int i;
	char c;
};
int main()
{
	union Un un;
	printf("%d \n", &(un.i));
	printf("%d \n", &(un.c));

	un.i = 1;
	un.c = 2;
	printf("%d \n", un.i);
	return 0;
}

 实例:判断当前机器的大小端?

int Pd()
{
	union
	{
		int i;
		char c;
	}un = { .i = 1 };
	return un.c;
}
int main()

{
	int ret = Pd();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

 4.3联合体大小的计算

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

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

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

相关文章

第G1周:生成对抗网络(GAN)入门

目录 一、课题背景和开发环境二、理论基础1.生成器2. 判别器3. 基本原理 三、前期准备工作1. 定义超参数2.下载数据3. 配置数据 四、定义模型1. 定义鉴别器2. 定义生成器 五、训练模型1. 创建实例2. 训练模型3. 保存模型 🍨 本文为🔗365天深度学习训练营…

检测到目标Content-Security-Policy响应头缺失

详细描述 HTTP 响应头Content-Security-Policy允许站点管理者控制用户代理能够为指定的页面加载哪些资源。除了少数例外情况,设置的政策主要涉及指定服务器的源和脚本结束点。 Content-Security-Policy响应头的缺失使得目标URL更易遭受跨站脚本攻击。 解决办法 …

浅谈炼钢厂能源计量管理系统的设计与应用

安科瑞 华楠 摘要: 从能源计量和管理的角度,论述了炼钢厂的能源计量管理系统的基本组成及功能。该系统的建立,将使炼钢厂能源介质的计量管理工作实现自动采集、瞬时监测、故障报警、能流监视;完成报表统计、离线输入、成本分析、预测参考等功…

【正点原子STM32连载】 第五十五章 录音机实验摘自【正点原子】STM32F103 战舰开发指南V1.2

1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id609294757420 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html# 第五…

大学生用一周时间给麦当劳做了个App(Flutter版)

背景 有个大学生粉丝最近私信联系我,说基于我之前开源的多语言项目做了个仿麦当劳的项目,虽然只是个样子货,但是收获颇多,希望把自己写的代码开源出来供大家一起学习进度。这个小伙伴确实是非常积极上进,很多大学生&a…

Django admin管理工具TabularInline表格内联

详解 TabularInline 是 Django Admin 中的一个内联模型选项,用于在父模型的编辑页面中以表格形式显示关联的子模型对象。下面是对 TabularInline 的一些详解: 显示方式:TabularInline 以表格的形式显示子模型对象。每个子模型对象将以一行的…

12.0、Java_IO流 - 字节数组输入输出流

12.0、Java_IO流 - 字节数组输入输出流 字节数组流: ByteArrayInputStream 和 byteArrayOutputStream 经常用在需要流和数组之间转化的情况; 字节数组输入流: 说白了,FileInputStream 是把文件当做数据源;ByteArrayInp…

变动率ROC指标详解及改进版选股公式

ROC指标(变动率指标)是一种基于动量的技术指标,衡量当前价格与一定天数前价格之间变化的百分比。ROC指标围绕零轴上下波动,如果价格变化向上,指标会移动到零轴之上;如果价格变动向下,则指标会移…

NestJS 编写 SSE 接口推送数据

做项目的时候遇到了顺便就记一下相关的内容。 SSE Server-Sent Events(SSE)技术,它是一种用于实现服务器向客户端实时推送数据的Web技术。SSE基于HTTP协议,允许服务器将数据以事件流(Event Stream)的形式…

深度学习(29)—— DETR

深度学习(29)—— DETR DETR代码欢迎光临Jane的GitHub:在这里等你 看完YOLO 之后,紧接着看了DETR。作为Transformer在物体检测上的开山之作,虽然他的性能或许不及其他的模型,但是想法是OK的。里面还有一些…

数据结构day1(2023.7.13)

一、Xmind整理: 二、课上练习: 练习1:static(全局变量、局部变量作用域) int a0;//全局变量 生命周期和作用于都是从定义开始到整个文件结束 void fun() { int b0;//局部变量 static int c0;//局部变量 作用于&#x…

智头条|第25届中国建博会(广州)成功举行,马斯克组建xAI公司

行业动态: 第25届中国建博会(广州)成功举行 7月8日至11日期间,2023中国建博会(广州)暨首届广州卫博会在广州如火如荼地进行。本届展会以“冠军企业首秀平台”为定位,以“建装理想家,服务新格局”为主题&a…

我的创作纪念日——创作的第2048天

创作机缘 今天收到私信,在CSDN已经7年码龄,创作2048天了,刚开始写作的时候似乎还是在大二,那个懵懂无知的年纪,也是在那个时候开始接触开发,接触编程。 之后便是无尽的探索与尝试,没有明确的发…

DuiLib的消息传递机制

前言 学会了怎么写XML文件,但是我还是不知道怎么实现各个控件之间的消息传递。于是我对源代码好好研究了一下,发现duilib作为一个界面库有自己独立的封装的窗口类,也就是WindowsImplBase。 在这个类中,实现对windows窗口传过来的消息的处理…

【每日一题】2673. 使二叉树所有路径值相等的最小代价

【每日一题】2673. 使二叉树所有路径值相等的最小代价 2673. 使二叉树所有路径值相等的最小代价题目描述解题思路 2673. 使二叉树所有路径值相等的最小代价 题目描述 给你一个整数 n 表示一棵 满二叉树 里面节点的数目,节点编号从 1 到 n 。根节点编号为 1 &#…

前端day06笔记

数组遍历 for let i in 数组名 函数 没有return返回的是underfined var是全局作用域 匿名函数 具名函数 值传递 引用传递 arguments:接实参 箭头函数 递归 闭包 对象的增删改查 对象的遍历 数组对象 获取数组对象 内置对象 从2-10

保险企业如何做好数据安全合规与敏感数据保护

监管部门多次“重拳出击”,保险企业如何做好敏感数据保护工作? 继《个人信息保护法》、《中华人民共和国消费者权益保护法》、《中国银保监会办公厅关于印发银行保险机构信息科技外包风险监管办法的通知》、《互联网保险业务监管办法》等相关法规之后&am…

CNN从搭建到部署实战(pytorch+libtorch)

模型搭建 下面的代码搭建了CNN的开山之作LeNet的网络结构。 import torchclass LeNet(torch.nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv torch.nn.Sequential(torch.nn.Conv2d(1, 6, 5), # in_channels, out_channels, kernel_sizetorch.nn.Sig…

mysql 第三章

目录 1.索引 2.事务 3.总结 1.索引 2.事务 3.总结 事务是一种机制,一个操作序列。包含了一组数据库操作命令。

静态数码管——FPGA

文章目录 前言一、数码管1、数码管简介2、共阴极数码管or共阳极数码管3、共阴极与共阳极的真值表 二、系统设计1、模块框图2、RTL视图 三、源码1、seg_led_static模块2、time_count模块3、top_seg_led_static(顶层文件) 四、效果五、总结六、参考资料 前言 环境: 1、…