【C语言】自定义类型

目录

一、结构体:

1、结构体的声明:

2、结构体的自引用:

3、结构体变量的定义和初始化:

4、结构体内存对齐:

5、结构体传参:

6、位段:

二、枚举类型:

三、联合体:


一、结构体:

1、结构体的声明:

首先要了解什么是结构:

结构是一些值的集合,与数组不同的是结构的每一个成员变量可以使不同类型的变量。

其声明的时候用struct关键字加上名字,如下定义一个学生的结构体:

struct Student
{char name[20];int age;char sex[10];char id[20];
};

拓展:也可以声明为匿名结构体(就是没有名字的结构体),这种类型的结构体就没有办法使用了,只有在这种类型后面直接定义变量。

struct 
{char name[20];int age;char sex[10];char id[20];
}s1,s2;

如上,这就定义了一个匿名结构体,其定义了s1,s2这样的全局变量,就可以在函数中使用

2、结构体的自引用:

如果在一个结构体中嵌套一个结构体,那么并不是直接在结构体中直接嵌套一个结构体的,因为这样的话,这个结构体的大小就会计算不了(结构体嵌套一个结构体,嵌套一个结构体里面又会有一个结构体,就会计算不了)那么,就需要在一个结构体中,存放执行向下一个结构体的指针,这样的话大小就可以计算了。

struct Node
{int a;struct Node* next;
};

3、结构体变量的定义和初始化:

1、可以在声明类型的同时定义变量:

struct Student
{char name[20];int age;char sex[10];char id[20];
}s1,s2;

2、可以在全局变量域中定义,并且在定义的同时赋初始值:

struct Node
{int x;int y;
}s1,s2;struct Node s3 = {3,5};

3、若在结构体中引用另一个结构体并初始化:

struct Node1
{int a;int b;
};struct Node2
{char x;struct Node1;float y;
};struct Node2 node = { 'w', { 1,2 }, 3.14f };

4、结构体内存对齐:

结构体对齐规则:
1、第一个成员在与结构体变量偏移量为0的地址处。
2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数:编译器默认的对齐数(VS上是8)和该成员大小的 较小值
        可以用pragma pack(N)来修改默认对齐数,N是几,默认对齐数就修改为几,
pragma pack()这串代码就是取消设置的默认对齐数,还原为默认
3、结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,
结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

那么为什么会有结构体对齐的规则呢?

在大多数资料都是这么说的:

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

例如:

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

5、结构体传参:

从代码入手:

struct S
{int data[1000];int num;
};struct S s = { {1,2,3,4,5,6,7},13 };void print1(struct S s)
{printf("%d\n", s.num);
}void print2(struct S* s)
{printf("%d\n", s->num);
}
int main()
{print1(s);print2(&s);return 0;
}

在如上代码中,print1就是传结构体即可,print2就是传结构体地址的。

建议:

由于在函数传参的时候,参数是需要压栈的,会有时间和空间上的系统开销,此时如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降,所以在结构体传参的时候,能传结构体的地址就传结构体的地址。

6、位段:

我们首先来看看位段是怎么定义的:

struct PPR
{int a : 2;int b : 6;int c : 13;int d : 31;char e : 7;unsigned int f : 2;
};

如上所示,

注意:

1、位段的成员必须是整型:int, unsigned int ,char等。

2、位段成员后面加上一个:和数字,来表示这个成员占有几个比特位(不能超过变量本身)

部分成员也可以不加冒号和数字。

理解:

位段时根据后面比特位的大小来给空间的,如:

struct PPR
{int a : 2;int b : 6;int c : 13;int d : 31;char x : 2;char e : 7;
};

对于上诉代码的位段理解:

首先第一个成员是int,就开辟32个比特位,接着把a,b,c可以都存放进去(2+6+13<32)

此时d的话放不进去,那么就在开辟32个比特位,将d存放进去。

在进行判断,发现只剩下一个比特位,x存放不进去,就在开辟char类型(8个比特位),然后将x放进去,在判断发现还剩下6个比特位,小于e,就在开辟8个比特位,将e存放进去。

以上就是位段的存放,但是位段有跨平台的问题:

1、int位段被当成有符号数还是无符号数是不确定的

2、位段中最大位的数目不能够确定(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题)

3、位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4、当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

二、枚举类型:

枚举类型就是将有限的值一 一列举出来,比如:星期,月份等等。

1、定义:用关键字enum来定义,总体和结构体大差不差,

例如星期的定义:(各个枚举常量之间用逗号隔开,最后一个枚举常量后面不需要逗号)

enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};

2、理解:

这些枚举常量都是有值的,如果均没有赋值就从0开始向下一次增加1;

也可以随便赋值(整型),也是依次向下增加1。

3、优点:

(1)增加代码的可读性和可维护性
(2)和 #define 定义的标识符比较枚举有类型检查,更加严谨。
(3)防止了命名污染(封装)
(4)便于调试

(5)使用方便,一次可以定义多个常量

三、联合体:

联合体也叫共用体,里面的那些成员变量共用同一块空间,

例如:

union Un
{char x;int i;
};

1、特点:

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
但是当最大成员的大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。
例如:
union u1
{char arr[5];int i;
};union u2
{short arr[7];int i;
};int main()
{printf("%d\n", sizeof(union u1));printf("%d\n", sizeof(union u2));return 0;
}

如上所示:

u1中:char arr[5]这个最大对齐数为1成员大小为5

            int i这个最大对齐数为4成员大小为4,

综合来看:大小应该为5,又要是最大对齐数的整数倍,所以大小就是8.

u2中:short arr[7]这个最大对齐数为2成员大小为14

            int i这个最大对齐数为4成员大小为4,

综合来看:大小应该为14,又要是最大对齐数的整数倍,所以大小就是16./2.

2、应用:

判断计算机的大小端:

int main()
{union Un{int i;char a;}un;un.i = 1;if (un.a == 1)printf("小端\n");elseprintf("大端\n");return 0;
}

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

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

相关文章

【深度学习驱动流体力学】完整配置安装 OpenFOAM 及其所需的ThirdParty与QT5工具

OpenFOAM 简介 OpenFOAM(Open Field Operation and Manipulation)是一个领先的开源计算流体动力学(CFD)软件包,由 OpenFOAM Foundation 开发和维护。作为一个高度模块化和可扩展的软件工具箱,OpenFOAM 支持模拟多种物理现象,包括流体流动、传热、混合、燃烧、声学等。由…

【设计模式深度剖析】【10】【行为型】【状态模式】

&#x1f448;️上一篇:访问者模式 | 下一篇:解释器模式&#x1f449;️ 设计模式-专栏&#x1f448;️ 文章目录 状态模式定义英文定义直译如何理解呢&#xff1f; 状态模式的角色Context&#xff08;环境类&#xff09;State&#xff08;抽象状态类&#xff09;Concret…

Java | Leetcode Java题解之第169题多数元素

题目&#xff1a; 题解&#xff1a; class Solution {public int majorityElement(int[] nums) {int count 0;Integer candidate null;for (int num : nums) {if (count 0) {candidate num;}count (num candidate) ? 1 : -1;}return candidate;} }

SpringCloud微服务框架的原理及应用详解(一)

本系列文章简介&#xff1a; 随着云计算、大数据和物联网等技术的飞速发展&#xff0c;企业应用系统的规模和复杂度不断增加&#xff0c;传统的单体架构已经难以满足快速迭代、高并发、高可用性等现代业务需求。在这样的背景下&#xff0c;微服务架构应运而生&#xff0c;成为了…

Netdata介绍

前言 Netdata是一款用于Linux系统的实时性能监测工具&#xff0c;它提供了web界面的视角&#xff0c;使得用户可以通过可视化的方式清晰地了解系统和应用程序的实时状态。 Netdata具有以下几个显著特点&#xff1a; 实时性&#xff1a;Netdata能够实时监测系统和应用程序的性…

Android-Android Studio-FAQ

1 需求 2 接口 3 Android Studio xml布局代码补全功能失效问题 最终解决方案就是尝试修改compileSdk 为不同SDK版本来解决问题&#xff0c;将原本34修改为32测试会发现xml代码补全功能有效了&#xff01; 参考资料 Android Studio xml布局代码补全功能失效问题_android studi…

电压调整+无功优化!考虑泄流效应的风电场并网点电压系统侧增援调控方法程序代码!

前言 在发电侧能源结构转型的背景下&#xff0c;中国在可再生能源发电技术上的快速发展使得电网中风电并网比例不断增大。风能资源的有效利用缓解了电力紧张&#xff0c;但由于风速的不确定性&#xff0c;风电场引起的公共耦合点&#xff08;point of common coupling&#xf…

vue3项目使用Electron打包成exe的方法与打包报错解决

将vue3项目打包成exe文件方法 一、安装 1.安装electron npm install electron --save-devnpm install electron-builder --save-dev 2.在vue项目根目录新建文件index.js // index.js// Modules to control application life and create native browser window const { app…

Map-JAVA面试常问

1.HashMap底层实现 底层实现在jdk1.7和jdk1.8是不一样的 jdk1.7采用数组加链表的方式实现 jdk1.8采用数组加链表或者红黑树实现 HashMap中每个元素称之为一个哈希桶(bucket),哈希桶包含的内容有以下4项 hash值&#xff08;哈希函数计算出来的值&#xff09; Key value next(…

基于SSM+Jsp的水果销售管理网站

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

Linux 五种IO模型

注&#xff1a;还有一种信号驱动IO&#xff0c;使用较少暂不讨论&#xff1b; 一&#xff0c;区分阻塞、非阻塞和同步、异步 看了很多文章对这两组概念解释和对比&#xff0c;说的太复杂了&#xff0c;其实没必要&#xff0c;两句话就能说清楚。 首先&#xff0c;对于读数据rec…

探索监管沙箱在金融科技行业中的应用

一、引言 随着金融科技的快速发展&#xff0c;传统金融机构与科技企业之间的竞争也日趋激烈。为了平衡金融科技创新与风险防控&#xff0c;各国监管机构纷纷引入监管沙箱&#xff08;Regulatory Sandbox&#xff09;机制。监管沙箱作为一个受监督的安全测试区&#xff0c;允许金…

在超线程CPU上切换到另一个线程

在超线程CPU上切换到另一个线程&#xff0c;主要涉及到的是上下文切换的过程。超线程技术允许单个CPU核心同时执行多个线程&#xff0c;提高了CPU的并行计算效率。当需要从一个线程切换到另一个线程时&#xff0c;CPU会进行一系列的操作来确保线程之间的顺利切换。 首先&#…

Linux字节对齐小程序

#include <stdio.h> // 默认对齐 struct DefaultAligned { char c; int i; }; // 按1字节对齐 #pragma pack(push, 1) struct OneByteAligned { char c; int i; }; #pragma pack(pop) // 恢复之前的对齐设置 int mai…

linux基础 - 内核的基础概念

目录 零. 前言 一. 源码简介 二. 存储管理 物理内存管理&#xff1a; 虚拟内存管理&#xff1a; 内存分配与回收&#xff1a; 三. CPU 和进程管理 进程管理&#xff1a; CPU 管理&#xff1a; 四. 文件系统 文件系统的概念 常见的 Linux 文件系统类型 文件系统的工…

Python日志管理利器:如何高效管理平台日志

一、为什么需要日志管理&#xff1f; 日志是应用程序的重要组成部分&#xff0c;它记录了应用程序的运行状态、错误信息以及用户交互等关键信息。良好的日志管理可以帮助开发人员及时发现和解决问题&#xff0c;提高应用程序的稳定性和可靠性。 项目在本地开发调试时&#xf…

Redis 有序集合(sorted set)

Redis 有序集合(sorted set) 引言 Redis&#xff0c;作为一个高性能的键值对数据库&#xff0c;提供了多种数据结构来满足不同的需求。其中&#xff0c;有序集合&#xff08;sorted set&#xff09;是一种特别的数据结构&#xff0c;它不仅具有集合&#xff08;set&#xff0…

CSS 计数器

CSS 计数器 CSS 计数器是 CSS 中一个强大但经常被忽视的功能。它们允许开发者创建和管理计数器,这些计数器可以在文档中自动递增,非常适合用于编号章节、列表项或其他文档元素。在本文中,我们将深入探讨 CSS 计数器的使用方法、优势和实际应用场景。 CSS 计数器的基本概念…

基于Sringboot+Vue的校园招聘系统【原创】【开源】

浏览器&#xff1a;Chrome或360浏览器 系统环境配置 前置条件&#xff1a;系统已经安装了Mysql5.7、Mysql工具&#xff08;Navicat&#xff09;、JDK1.8、Maven3.6.1、vue3.0以下开发环境、 Intellij Idea、 Chrome或360浏览器 1、导入数据库 2、编译前端代码vue 编译&…

C++笔记之通过CMakeLists.txt像使用boost库一样使用qt库中特有的模块来方便开发

C++笔记之通过CMakeLists.txt像使用boost库一样使用qt库中特有的模块来方便开发 code review! 文章目录 C++笔记之通过CMakeLists.txt像使用boost库一样使用qt库中特有的模块来方便开发1.文件结构2.CMakeLists.txt3.main.cpp4.运行1.文件结构 . ├── CMakeLists.txt └──…