C语言自定义类型详解(结构体 枚举 联合)

2023-10-31

目录

1.结构体类型

1.1声明

1.2结构的自引用

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

1.4结构体内存对齐

1.4.1结构体的对齐规则

1.4.2编译器的默认对齐数修改

1.5结构体传参

1.6结构体实现位段(位段的填充&&可移植性)

1.6.1位段的定义

1.6.2位段的内存分配

1.6.3位段的跨平台问题

1.6.4位段的应用->ip数据报

2.枚举

2.1枚举类型的定义

2.2枚举的优点

3.联合(共用体)

3.1联合类型的定义

3.2联合的特点

3.3联合大小的计算

1.结构体类型

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

1.1声明

struct tag   //struct是结构体关键字。tag是结构体名,自取
{
    member-list;    //成员变量
}variable-list;  //该结构体类型的变量(可省),分号不能丢
//若结构体放在函数之外,则表示全局声明,后面跟的变量也是全局变量

//第二种写法->匿名结构体类型
struct   //结构体名字被省略
{
    member-list;    //成员变量
}variable-list;  //该结构体类型的变量(不可省),分号不能丢
//第二种只能在声明的同时创建变量,只能用一次
//且声明两次相同的结构体类型创建的变量,编译器仍然判断这两个变量为不同类型

//第三种->结构体名的重定义
typedef struct tag   //struct是结构体关键字。tag是结构体名,自取
{
    member-list;    //成员变量
}Node;  //此时Node就是重命名后的名称
//以后定义该结构体类型的变量可以这样写->Node n1;
//类似的,下面实现对指针类型的结构体变量命名
typedef struct tag   //struct是结构体关键字。tag是结构体名,自取
{
    member-list;    //成员变量
}* Linklist;

1.2结构的自引用

举例:

struct Node{
  int date;
  struct Node* next;
  //不能在结构体类型内定义自身结构体变量,否则sizeof()无法计算大小  
};

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

举例:

//方式1
struct Node(
    int num1;  
    int num2;
)p1 = {1,2};
//方式2
struct Node(
    int num1;  
    int num2;
);
struct Str(
    char str[20];  
    int num2;
    struct Node* node;
);
int mian(){
    struct Node s1 = {1,2};
    struct Str s2 = {"zhangsan",23,{1,2}};
    return 0;
}

初始化时使用“{}”包含成员变量,可不完全初始化

1.4结构体内存对齐

1.4.1结构体的对齐规则

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

代码1:

struct S1
{
    char c1; //1
    int i;  //4
    char c2; //1
};

图解:

 代码2:

struct S2
{
    char c1; //1
    char c2; //1
    int i;  //4
};

图解:

 代码3:

struct S3
{
    char c1;
    struct S2 s2;
    double d;
};

图解:

存在内存对齐的原因:

  • 平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

  • 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说:

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

由S1和S2可得到结论:让占用空间小的成员尽量集中在一起,可以既满足对齐,又节省空间

1.4.2编译器的默认对齐数修改

需要#pragma预处理指令

举例:

#include <stdio.h>
#pragma pack(8)  //设置默认对齐数为8
struct S1
{
    char c1;
    int i;   
    char c2;
};
#pragma pack() //取消设置的默认对齐数,还原为默认,之前设置的只对S1有影响

#pragma pack(1)  //设置默认对齐数为8
struct S2
{
    char c1;
    int i;   
    char c2;
};
#pragma pack() //取消设置的默认对齐数,还原为默认,之前设置的默认对齐数1只对S2有影响

1.5结构体传参

结构体传参包括值传参和地址传参

举例:

struct S
{
    int data[1000];
    int num;    
};
struct S s1 = {{0},1000};
void Print1(strcut S s)
{
    printf("%d\n",s.num);        
}
void Print2(struct S* s)
{
    printf("%d\n",s->num);
}
int main(){
    //方式1,值传递,参数过大时压栈并赋值临时变量既浪费空间,也浪费时间,性能下降
    Print1(s1);
    //方式二,地址传递,传递时只会传递一个地址,压栈时系统开销相对不大,所以传参时首选地址传递
    Print2(&s1);
    return 0;
}

1.6结构体实现位段(位段的填充&&可移植性)

相对节省空间的操作

1.6.1位段的定义

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

  1. 位段的成员必须是整型家族
  2. 位段的成员名后面有一个冒号和一个数字(数字不能超过类型的大小)

举例:

struct A //A就是一个位段类型
{
    int a:2; //只给a分配两个bit
    int b:5; //b分配五个bit
    int c:10; //10个bit
    int d:30; //30个bit
};

在VS2019编译器x86环境下中,位段A的大小为八个字节,64个bit

1.6.2位段的内存分配

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

举例:

struct A 
{
    char a:3; //给a分配3个bit
    char b:4; //b分配4个bit
    char c:5; //5个bit
    char d:4; //4个bit
};
struct A s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

分析(VS2019平台):

 通过查看内存显示证明:

1.6.3位段的跨平台问题

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

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

1.6.4位段的应用->ip数据报

2.枚举

将有限较少的可能的全部取值一一列举

2.1枚举类型的定义

举例:

enum Day //星期
{
    Mon,  //注意都是逗号
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun    //最后一个元素不用加逗号       
};
//本质上还是一种类型,只有定义出变量后才会分配空间
//经笔者验证,这种写法需要将定义放在需要它的文件内
int main(){
    enum Day d = Fri;  //创建enum Day变量并进行赋值时,赋值只能选择以上七个选项
    return 0;
}
  • {}中的内容是枚举类型的可能取值,也叫枚举常量
  • 这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义时也可赋初值

例如:

enum Day //星期
{
    Mon = 1,  //表示此时从1开始递增
    Tues,  //其他取值也可任意赋值,后续的值都是从前面最后一次赋值依次递增
    Wed,
    Thur,
    Fri,
    Sat,
    Sun 
};
int main(){
    enum Day d = Fri;  //此时Fri = 5
    return 0;
}

2.2枚举的优点

  • 增加代码的可读性和可维护性

比如代码运行在菜单界面后用户做出选择,代码编写时用枚举中的可能取值代替数字,可以让程序员逻辑更清晰

  • 和#define定义的标识符比较枚举有类型检查,更加严谨

#define定义的标识符无符号,枚举定义出来的就是枚举类型,只能用枚举类型中的可能取值进行赋值,而不能用数字等等(C语言或许语法要求不严格,.c不报错,C++严格,.cpp会报错)

  • 防止了命名污染(封装)
  • 便于调试

但枚举类型可以在调试中看到

  • 使用方便,一次可以定义多个常量(不用一直#define)

3.联合(共用体)

3.1联合类型的定义

联合也是一种特殊的自定义类型

这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间(所以联合也叫共用体)

举例:

#include <stdio.h>
//联合类型的声明
union Un
{
	char c;
	int i;
};
//两个成员不能同时用
int main() {
	//联合类型的定义
	union Un un;
	//计算联合变量的大小
	printf("%d\n", sizeof(un));
	printf("%p\n", &un);
	printf("%p\n", &un.c);
	printf("%p\n", &un.i);
	return 0;
}

运行结果:

原因:

3.2联合的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小

确认当前计算机大小端存储方法2:

//联合实现
int check_sys() {
	union {
		int i;
		char ch;
	}nn;
	nn.i = 1;
	return nn.ch;
}

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

3.3联合大小的计算

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

举例:

union Un {
	char str[5];  //5
	int i;  //4
};

int main() {
	union Un un;
	printf("%d", sizeof(un));
	return 0;
}

运行结果:

原因:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言自定义类型详解(结构体 枚举 联合) 的相关文章

  • 软件测试|Python中如何提取列表中索引为奇数的元素

    简介 在Python中 我们经常需要从列表中提取特定位置的元素 如果我们想要提取列表中索引为奇数的元素 可以使用一些简单的方法来实现这一目标 本文将介绍如何在Python中提取列表中索引为奇数的元素 并提供示例代码来帮助大家更好地理解这个过
  • 让CHAT介绍下V2ray

    CHAT回复 V2Ray是一个网络工具 主要用于科学上网和保护用户的网络安全 它的名字源自Vmess Ray 光线 通过使用新的网络协议 为用户提供稳定且灵活的代理服务 下面是一些V2Ray的主要特性 1 多协议支持 V2Ray 提供了大量
  • 软件测试|使用matplotlib绘制平行坐标系图

    简介 绘制平行坐标系图 Parallel Coordinates Plot 是一种用于可视化多维数据的强大方法 在这篇文章中 我们将介绍如何使用Matplotlib库创建平行坐标系图 以及如何解释和定制这种图表 我们将使用一个示例数据集来演
  • 用CHAT分析高校体育智慧教学体系构建与探索研究现状

    CHAT回复 现阶段 高校体育智慧教学体系的构建与探索研究还处于初级阶段 但全球数字化转型大潮的推动下 一些较为前沿的研究和实践已经开始出现 1 教学平台的建设 很多高校已经开始尝试使用在线教育平台进行体育教学 把传统的面对面授课模式转变为
  • 软件测试|教你使用Python下载图片

    前言 我一直觉得Windows系统默认的桌面背景不好看 但是自己又没有好的资源可以进行替换 突然我一个朋友提醒了我 网络上的图片这么多 你甚至可以每天换很多个好看的背景 但是如果让我手动去设置的话 我觉得太麻烦了 我不如使用技术手段将图片下
  • 【计算机毕业设计】电影播放平台

    电影播放平台采用B S架构 数据库是MySQL 网站的搭建与开发采用了先进的java进行编写 使用了springboot框架 该系统从两个对象 由管理员和用户来对系统进行设计构建 主要功能包括 个人信息修改 对用户 电影分类 电影信息等功能
  • 【计算机毕业设计】毕业生就业管理微信小程序_lm9q0

    腾讯公司在2017年1月19日发布了一款不需要下载 不需要卸载 不需要存储的软件叫微信小程序 受到了很多人的喜欢 微信小程序自2017年发布至今 依托微信的社交属性和庞大的用户基数 已经渗透到生活的方方面面 1 微信小程序可以将基于微信平台
  • 华为OD机试 Java 【计算文件大小】

    题目 一个电脑文件夹系统 每个文件夹里都有一些文件和可能还有其他子文件夹 给定所有文件夹的大小和子文件夹列表 你的任务是找出某一个文件夹及其所有子文件夹里的文件总大小 输入格式 首行有两个数字 文件夹的总数M和你要查询的文件夹ID N 之后
  • 【硕士论文复现】可再生能源发电与电动汽车的协同调度策略研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 1 1 上层问题 1 2 下层问题 2 运行结果
  • 计算机Java项目|springboot校园台球厅人员与设备管理系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 计算机Java项目|电影购票系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • JCMsuite应用:光学环形谐振腔模拟

    本案程演示了环形谐振腔的模拟 这种类型的集成光子器件 例如用作升 降滤波器或在传感应用中 当物质或粒子附着在环上时 通过测量其共振频率的位移来检测 对于集成光子电路中的无源光器件 s矩阵通常是研究的热点 它描述了通过端口 波导进入设备的电磁
  • 用栈实现队列(OJ中报错的处理)

    用栈实现队列 ERROR AddressSanitizer myQueueFree函数中栈的释放处现了问题 没有调用StackDestory而是直接free了 这个是栈初始化时 capacity与malloc申请的空间大小没有匹配 请你仅使
  • 基于节点电价的电网对电动汽车接纳能力评估模型研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据
  • 2024年华为OD机试真题-靠谱的车-Python-OD统一考试(C卷)

    题目描述 程序员小明打了一辆出租车去上班 出于职业敏感 他注意到这辆出租车的计费表有点问题 总是偏大 出租车司机解释说他不喜欢数字4 所以改装了计费表 任何数字位置遇到数字4就直接跳过 其余功能都正常 比如 1 23再多一块钱就变为25 2
  • 初学者如何快速入门Python(内附详细攻略),一文讲清

    目前python可以说是一门非常火爆的编程语言 应用范围也非常的广泛 工资也挺高 未来发展也极好 Python究竟应该怎么学呢 我自己最初也是从零基础开始学习Python的 给大家分享Python的学习思路和方法 一味的买书看书 看视频 是
  • 计算机Java项目|有机蔬菜商城

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 【js学习之路】遍历数组api之 `filter `和 `map`的区别

    一 前言 数组是我们在项目中经常使用的数据类型 今天我们主要简述作用于遍历数组的api filter 和 map 的区别 二 filter和map的共同点 首先 我们主要阐述一下 filter 和 map 的共同点 api的参数都是回调函数
  • 在 Python 中实现 List 抽象

    在 Python 中 创建一个包含多个对象的 list 很常见 例如 对于一组具有相同功能的对象 比如播放声音 希望能够使用类似 my list play 的语法来触发 list 中所有对象的 play 方法 另一个例子是 当希望关闭 li
  • Java进阶之旅第七天

    Java进阶之旅第七天 文章目录 Java进阶之旅第七天 方法引用 介绍 代码展示 结果 方法引用的分类

随机推荐

  • 指令延迟隐藏

    一 指令延迟隐藏 1 延迟和延迟隐藏 指令延迟指计算指令从调度到指令完成所需的时钟周期 如果在每个时钟周期都有就绪的线程束可以被执行 此时GPU处于满符合状态 指令延迟被GPU满负荷计算状态所掩盖的现象称为延迟隐藏 延迟隐藏对GPU编程开发
  • 安装docker报错

    安装docker报错如下 解决办法 rm f var run yum pid
  • Kubernetes -K8S安装部署及SpringCloud应用

    k set image deploy kubia nodejs luksa kubia v2 一 Kubernetes 一键安装Kubernetes集群 集群方案 使用三台物理机或VMware虚拟机来搭建集群环境 一台主控服务器 两台工作节
  • 微信报错:40001: invalid credential, access_token is invalid or not latest rid: xxx(附带存储access_token代码)

    我使用的是redis作为存储服务器 来存储access token 代码亲测没有任何问题 在做微信公众号模板推送的时候用到了access token 但是有时推送成功 有时失败 报错显示为 40001 invalid credential
  • unity中vs编辑代码时没有自动补全的解决方案之一

    点击 unity编辑器中的 Edit选项 gt preferences gt External Tools 把选项改成这个就ok
  • Lambda 实战-集合分组统计

    package com lingoace edu util import lombok Data import java util ArrayList import java util List import java util LongS
  • ◆考试题目◆◇NOIP模拟赛◇turtle(乌龟)

    NOIP模拟赛 turtle Description 一只乌龟由于智商低下 它只会向左或向右走 不过它会遵循主人小h的指令 F 向前走一步 T 掉头 现在小h给出一串指令 由于小h有高超的计算能力 他可以马上知道乌龟最后走到哪里 为了难倒小
  • bitlocker 恢复密钥

    开机出现问题 需要bitlocker 恢复密钥 登录Microsoft官网自己的账号 我的Microsoft账户 有问题电脑的详细信息 登录 找到对应密钥填入
  • STANet基于时空自注意力的神经网络--变化检测模型

    STANet基于时空自注意力的神经网络检测模型 A spatial temporal attention based method and a new dataset for remote sensing image change dete
  • C#----使用继承选择器创建继承窗体

    欢迎大家提出意见 一起讨论 转载请标明是引用于 http blog csdn net chenyujing1234 代码 VS2008 http www rayfile com zh cn files 68b23066 9aab 11e1
  • mos管驱动电路设计

    对于开关电源来说 驱动电路作为控制电路和功率电路的接口 其作用至关重要 本文就将详细探讨开关电源的驱动电路的参数设计以及驱动芯片的选型 常用的mos管驱动电路结构如图1所示 驱动信号经过图腾柱放大后 经过一个驱动电阻Rg给mos管驱动 其中
  • 集合nim(C++)

    题目 给定 n 堆石子以及一个由 k 个不同正整数构成的数字集合 S 现在有两位玩家轮流操作 每次操作可以从任意一堆石子中拿取石子 每次拿取的石子数量必须包含于集合 S 最后无法进行操作的人视为失败 问如果两人都采用最优策略 先手是否必胜
  • RFID标签打印机在加工制造业中的应用

    1 行业背景 在物联网家电制造 机械制造 电子元器件 电器等产品加工制造行业中 通常都需要打印标签直接贴到产品上 如 铭牌标签 条码序列号标签 合格证标签 电路图标签 RFID标签等等 传统的部分企业的这些标签是印刷后粘贴到产品上 但是随着
  • 从小白到专家的五个阶段,你处在哪里?

    专家和新手的区别在哪里 每一个程序员都有一个梦想 成为领域内的专家 专家和新手有什么不同 1970年代左右 德雷福斯兄弟通过对飞行员 国际著名象棋大师的技能习得进行研究 他们发现专家和新手在技能调用上有很大的不同 并提出了德雷福斯模型 Dr
  • OpenStack中glance对接swift

    OpenStack中glance对接swift 一 环境介绍 二 查看数据库中glance相关信息 1 查询数据库glance用户密码 2 登录数据库 3 查询glance相关数据库 4 查询glance数据库表 5 查询image loc
  • HikariCP MBean (JMX) Monitoring and Management

    The JMX MBean for HikariCP exposes Idle Connection count Active Connections in use Total Connections The number of threa
  • 本地下载的软件包制作成本地repo源并使用apache发布

    背景 在前面的博客中 介绍了如何使用apt mirror同步远程的repo源 本文将介绍如何利用本地已经缓存的软件包制作成本地repo源 并对外提供源服务 应用目标 在应用中 有时候会遇到类似问题 远程的软件源太慢 而如果同步远程的软件源到
  • 国标GB28181协议视频平台EasyGBS内网访问正常,公网无法访问是什么原因?

    国标视频云服务平台EasyGBS可支持通过国标GB28181协议 接入多路视频源设备 实现视频流的接入 转码 处理与分发等功能 对外输出的视频流格式包括RTSP RTMP FLV HLS WebRTC等 平台视频能力丰富灵活 包括监控直播
  • XML中PCDATA与CDATA的区别

    XML中PCDATA与CDATA的区别 2011 02 10 19 27 25 分类 XML 标签 xml中pcdata与cdata的区别 字号 大中小 订阅 所有 XML 文档中的文本均会被解析器解析 只有 CDATA 区段 CDATA
  • C语言自定义类型详解(结构体 枚举 联合)

    目录 1 结构体类型 1 1声明 1 2结构的自引用 1 3结构体变量的定义和初始化 1 4结构体内存对齐 1 4 1结构体的对齐规则 1 4 2编译器的默认对齐数修改 1 5结构体传参 1 6结构体实现位段 位段的填充 可移植性 1 6