自定义类型知识详解(结构体,位段,枚举,联合体)

news2024/11/15 17:54:29

目录

结构体

        定义,初始化,自引用

        内存对齐,修改默认对齐数

        传参

位段

        位段内存问题

        跨平台及其应用问题

枚举

        定义,初始化

        实战举例使用及其优点

联合体

        联合体定义

        特点

        大小计算问题


结构体

        定义,初始化,自引用

1:结构体的定义:

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

2:初始化:

三种初始化方式,被注释掉的代码只有在支持C99的编译器下才可以使用,他是乱序初始化,我们常用的是顺序初始化。

#include <stdio.h>

struct Student
{
	char name[8];
	int age;
	char sex[4];
}a = {"haha",4,"nan"};           //第一种


int main()
{
	struct Student c = { "gaga",6,"?" };   //第二种
	//struct Student b = { .age = 5, .name = "hehe", .sex = "nu" };   //第三种

	return 0;
}

这里还有一种特殊的声明方式: 

 这样声明的话只能在这里进行初始化,因为他没有名字,后面再想使用这个结构体,没有名字就无法创建该类型变量。

3:结构体的自引用:

这是错误用例,如果这样写的话,那么sizeof(struct Student)大小是多少呢?这样是算不出来的。

 接下来我们看正确用例:

这样,就是一个指针,指向这个结构体类型,就不会出现上面无限套娃的情况,再往后面加其实就是一个链表了。

再看重命名后的错误用例:

 Stu前面的代码(typedef是重命名,不算在类型里)都是这个结构体类型,也就是说Stu在结构体里是未定义的,然后去使用Stu,这是错误的,改正:

        内存对齐,修改默认对齐数

这里我们将说到结构体的大小计算,涉及到结构体的内存对齐。

我们先看一下这个结构体的大小,各位也可以先计算一下,看看结果是否正确。

 正确答案是:12个字节,你算对了吗?

结构体对齐规则:

        1:第一个成员变量在与结构体偏移量为0的位置。

 2:每个成员变量要对齐到他们各自的对齐数的整数倍处,也就是说偏移量是其对齐数的整数倍,起始偏移量为0,对齐数的大小为其sizeof的大小与默认对齐数比较后取小者。

3:每个编译器都有默认对齐数,VS为8个字节,计算结构体总大小时要看其最大对齐数,取成员变量中最大的对齐数,在每个成员变量各自对齐后,结构体所占内存总大小是将总和补到最大对齐数的整数倍。

4:如果嵌套了结构体,则嵌套的结构体的最大对齐数为其自身的最大对齐数,对齐到自身最大对齐数的整数倍处。

接下来我们来计算这个案例 

char ch 占一个字节,VS默认对齐数为8,取小,对齐数为1, 放在开头,int a占4个字节,比8小,对齐数取4,4偏移量是4的倍数,从4位置开始分配四个字节的内存空间,short同理,8是2的整数倍,从该处分配内存空间。

结构体中成员变量的对齐数中最大为4,与默认对齐数8相比取4,最大对齐数为4,总大小为4的倍数,则取12个字节。(图中占用字节为7个字节,浪费5个字节,但这是有意义的

 内存对齐的意义:

1:平台的移植性:不是每个平台都能访问任意位置的地址上的任意数据。

2:性能原因:

总的来说,结构体内存对齐就是用空间换取时间的做法 

        传参:

结构体传参最好传指针,如果传值,实参的临时拷贝对栈区的压力会增大。

#include <stdio.h>
#include <string.h>

typedef struct T
{
	int a;
	char b;
}T;

void Test(T* stu)
{
	printf("haha:%d", stu->a);
}

int main()
{

	T stu;
	memset(&stu, 0, sizeof(T));

	Test(&stu);

	return 0;
}

位段

1:位段成员必须是int ,signed int,unsigned int(char也可以)

2:位段成员名后面有一个冒号和数字(分配的bit位)

 A就是一个位段类型。

        位段内存问题

位段涉及很多问题,比如读取数据的方向,空间不足时数据存部分还是不存。

位段的空间开辟是按照开辟四个字节(int),或一个字节(char)的方式

        跨平台及其应用问题

 

枚举

        定义,初始化

enum A
{
	Monday,
	Tuesday,
	Wednesday,
	Thursday,
	Friday,
	Saturday,
	Sunday
};

使用enum创建枚举类型,从第一个枚举常量开始,若不给定值,默认为0,后面的枚举常量依次加1,我们看结果:

 当然,我们也可以给枚举常量赋初值:

        实战举例使用及其优点

 只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

 当然,硬要强制转换也是可以的,不推荐。

一般来说我们也不这么用,真正要用是在switch语句中使用,每一个case后的常量换成枚举常量。

比如:

case 0:我们可以换成case Add:(假设Add是枚举常量的第一个)

这样我们看起来就会方便一些,不会说一看0,不清楚这是做什么的。

联合体

        联合体定义:

一种特殊的自定义类型,接下来看声明:

        特点:

所有成员共用同一块空间,他们的起始地址都相同:

 一个union联合体的大小,至少是最大成员的大小。

        大小计算问题

整体大小也要对齐到最大对齐数的整数倍,上面举例的联合体大小为4个字节。

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

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

相关文章

揭秘 ChatGPT:构建 AI 搜索的不同方法

作者&#xff1a;Sherry Ger 什么是 ChatGPT&#xff1f; 首先&#xff0c;ChatGPT 太棒了&#xff01; 它可以帮助你更高效地工作 —— 从总结 10,000 字的文档到提供竞争产品之间的差异列表&#xff0c;以及许多其他任务。 ChatGPT 是最著名的基于 Transformer 架构的大型语…

SpringBoot读取配置文件顺序

文章目录 一、前言二、SpringBoot配置文件目录读取顺序源码解析 三、SpringBoot配置文件类型读取顺序源码解析 一、前言 本文通过源码分析 SpringBoot 加载配置文件目录的顺序&#xff0c;以及 properties、xml、yml、yaml文件的读取顺序 二、SpringBoot配置文件目录读取顺序…

前端学习——Vue (Day7)

vuex 构建 vuex [多组件数据共享] 环境 state状态 mutations状态 mapMutations actions mapActions getters 模块 module (进阶语法) 综合案例 - 购物车 axios报错解决方案 import axios from axiosexport default {namespaced: true,state () {return {list: []}},mutations…

用户体系之账户设计

文章目录 前言一、需求分析1、登录功能2、退出功能3、账号绑定功能3、其他注意事项 二、账户设计1、表设计2、QA 三、实践1、账户密码登录2、手机号登录3、第三方授权登录4、账户统一 前言 随着互联网的发展&#xff0c;越来越多的应用、网站需要用户进行登录才能使用。为了方…

LeetCode 刷题 数据结构 数组 283题 移动零

难度&#xff1a;简单 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入:…

QGraphicsView实现简易地图2『瓦片经纬度』

前文链接&#xff1a;QGraphicsView实现简易地图1『加载离线瓦片地图』 地图采用GCJ02 Web 墨卡托投影&#xff0c;最小坐标&#xff1a;(-180.00000000000000,-85.05112877980655)&#xff0c;最大坐标&#xff1a;(180.00000000000000,85.05112877980655)。瓦片地图单张图片像…

如何通俗理解扩散模型?

扩散模型(Diffusion Model)是一类十分先进的基于扩散思想的深度学习生 成模型。生成模型除了扩散模型之外&#xff0c;还有出现较早的 VAE ( Variational Auto- Encoder&#xff0c;变分自编码器) 和 GAN ( Generative Adversarial Net &#xff0c;生成对抗网络) 等。 虽然它们…

Cpp学习——类与对象(2)

思维导图&#xff1a; 一&#xff0c;构造函数 1.定义 对于构造函数首先就要知道构造函数怎么写&#xff0c;构造函数怎么写呢&#xff1f;你要知道如下两点&#xff1a; 1.构造函数的函数名要与类名相同 2.构造函数是没有返回值的&#xff0c;但可以有参数。 因为这第二点&am…

ubuntu目录分析

在Ubuntu根目录下&#xff0c;以下是一些常见文件夹的含义&#xff1a; /bin&#xff1a;存放可执行文件&#xff0c;包含一些基本的命令和工具。 /boot&#xff1a;存放启动时所需的文件&#xff0c;如内核和引导加载程序。 /dev&#xff1a;包含设备文件&#xff0c;用于与硬…

关于计算机视觉的Open3D简介

一、说明 Open3D 是一个开源库&#xff0c;使开发人员能够处理 3D 数据。它提供了一组用于 3D 数据处理、可视化和机器学习任务的工具。该库支持各种数据格式&#xff0c;例如 .ply、.obj、.stl 和 .xyz&#xff0c;并允许用户创建自定义数据结构并在程序中访问它们。 Open3D 广…

【雕爷学编程】MicroPython动手做(16)——掌控板之图片图像显示

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

进程_PCB 的理解

目录 一. PCB 的概念 1. 为什么需要PCB 2. PCB的属性 二. task struct 1. task struct 介绍 2. 查看进程指令 3. PID 4. PPID 父进程是什么&#xff1f; 为什么要有父进程&#xff1f; 5. fork 创建子进程 1) fork 后的现象 为什么会打印两次&#xff1f; 2) 的返…

用C语言实现插入排序算法

1.设计思路 用插入排序对长度为n的待排序数组A进行排序的伪代码&#xff08;在代码中&#xff0c;A中元素的数目n用A.length来表示&#xff09;。 伪代码如下&#xff1a; INSERTION-SORT(A) for j2 to A.length:keyA[j] //将A[j]插入已排序序列A[1..j-1]ij-1while i>0…

【MTI 6.S081 Lab】Copy-on-write

【MTI 6.S081 Lab】Copy-on-write The problemThe solutionImplement copy-on-write fork (hard)实验任务Hints解决方案问题解决思考uvmcopykfreekallockpagerefcow_handlertrap 虚拟内存提供了一定程度的间接性&#xff1a;内核可以通过将PTE标记为无效或只读来拦截内存引用&a…

Quartz项目搭建与任务执行源码分析

数据库准备 准备一个MySQL数据库&#xff0c;版本为8.0&#xff0c;然后创建一个库&#xff0c;并从quartz官方的版本包中找到名称为tables_mysql_innodb.sql的脚本执行进去&#xff08;脚本内容文后也有提供&#xff09;。 项目依赖说明 创建一个Maven项目&#xff0c;引入…

Python方式实现简易弹道计算机

1 问题 本周无意间刷到了德国豹2A5坦克的火控介绍&#xff0c;想自己编写一个不考虑空气阻力以及测风影响的简易弹道计算机&#xff08;大口径火炮&#xff09;。 2 方法 由高中物理知识了解到&#xff0c;炮弹出膛之后基本就是抛物线列个抛物线方程就好了; 百度得火炮的弹道方…

【Django学习】(十六)session_token认证过程与区别_响应定制

一、认识session与token 这里就直接引用别人的文章&#xff0c;不做过多说明 网络应用中session和token本质是一样的吗&#xff0c;有什么区别&#xff1f; - 知乎 二、token响应定制 在全局配置表中配置 DEFAULT_AUTHENTICATION_CLASSES: [# 指定jwt Token认证rest_framew…

python_day17_多线程

threading模块 import timedef sing():while True:print("唱歌~~~~~~~~~~~~")time.sleep(1)def dance():while True:print("跳舞############")time.sleep(1) if __name__ __main__:sing()dance()此时为单线程 import threading import timedef sing(…

Java 异常处理的使用和思考

概念 异常处理的概念起源于早期的编程语言&#xff0c;如 LISP、PL/I 和 CLU。这些编程语言首次引入了异常处理机制&#xff0c;以便在程序执行过程中检测和处理错误情况。异常处理机制随后在 Ada、Modula-3、C、Python、Java 等编程语言中得到了广泛采用和发展。在 Java 中&a…

迁移学习《Efficient and Robust Pseudo-Labeling for Unsupervised Domain Adaptation》

1 摘要 问题&#xff1a;无监督域适应传统方法将超过一定置信度阈值的数据视为目标域的伪标记数据&#xff0c;因此选择合适的阈值会影响目标性能。 在本文中&#xff0c;提出了一种新的基于置信度的加权方案来获得伪标签&#xff0c;并提出了一种自适应阈值调整策略&#xff0…