当前位置: 首页 > news >正文

【C语言】进阶——结构体+枚举+联合

 ①前言:

在之前【C语言】初阶——结构体 ,简单介绍了结构体。而C语言中结构体的内容还有更深层次的内容。

一.结构体

结构体(struct)是由一系列具有相同类型或不同类型的数据项构成的数据集合,这些数据项称为结构体的成员。

 1.结构体的声明

// 创建结构体
struct student
{char name[10];  // 学生名字int num;     // 学生学号int age;     // 学生年龄
}stu;

struct student 是类型,stu是结构体类型变量

2.结构体的定义和初始化 

2.1结构体的初始化 
struct Stu         //类型声明
{char name[15];    //名字int age;          //年龄
};
struct Stu s = {"zhangsan", 20};    //初始化
 2.2结构体的自引用
struct Node
{int data;struct Point p;struct Node* next; 
}n1 = {10, {4,5}, NULL};     //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};    //结构体嵌套初始化

3.结构体内存对齐 

首先得掌握结构体的对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

        对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

        VS中默认的值为8

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

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

 

s1在内存中所占的字节大小是多少?

VS默认对齐数是8

Linux没有默认对齐数自身大小就是其对齐数

首先c1是char类型 占1个字节与8比,8大,对齐数是1,放在偏移量为0的位置

c2也是char 类型对其数是1放在1的整数倍处也就是放在偏移量为1的位置

i是int型占4个字节,最大对其数是4,放在偏移量为4的位置

最后s1偏移量为7一共占用了8个字节,8是最大偏移量4的整数倍,所以s1在内存中占用了8个字节

 3.1为什么存在内存对齐?

    结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到?
    让占用空间小的成员尽量集中在一起。 

1. 平台原因(移植原因):

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

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访 问。

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

3.2修改默认对齐数

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

3.3offsetof宏

用法:计算偏移量

头文件:#include <stddef.h> 

offsetof (type,member)
struct address {char name[50];char street[50];int phone;
};int main()
{printf("address结构中的name 偏移 = %d 字节\n", offsetof(struct address, name));//0字节printf("address结构中的street 偏移 = %d 字节\n", offsetof(struct address, street)); //50字节  
}
 👊模拟实现
//模拟实现宏offsetof
#define my_offsetof(struct_name, member_name)  (int)&(((struct_name*)0)->member_name)
//例如shtruct S{char a; char b;};
//用宏替换:(int)&(((struct S*)0)->a)
//解释:把结构体的首地址看成0,那么每个成员的地址(减去首地址0)也就是相对于首地址的偏移量,所以取到成员的地址并转换为int型就是偏移量;//注意:以上把0强制转换成struct S*类型之后(把0转换成一个结构体指针类型),那么从0地址往后看就是一个结构体的形式看
//也可以说是在0地址的位置上放了一个结构体;

注:结构体传参主要以传地址为主。

二.位段 

  1. 位指的是二进制位;
  2. 位段的成员必须是 int、unsigned int signed int、char
  3. 位段的成员名后边有一个冒号和一个数字;
  4. 可以使数据单元节省储存空间,当程序需要成千上万个数据单元时,这种方法就显得尤为重要;
  5. 不支持跨平台
struct str
{int _a : 2;int _b : 3;		//后面的数字是bit位,不是字节
};

 

int main()
{unsigned char puc[4];struct tagPIM{unsigned char ucPim1;unsigned char ucData0 : 1;unsigned char ucData1 : 2;unsigned char ucData2 : 3;}*pstPimData;pstPimData = (struct tagPIM*)puc;memset(puc, 0, 4);pstPimData->ucPim1 = 2;pstPimData->ucData0 = 3;pstPimData->ucData1 = 4;pstPimData->ucData2 = 5;printf("%02x %02x %02x %02x\n", puc[0], puc[1], puc[2], puc[3]);return 0;
}

puc是一个char数组,每次跳转一个字节,结构体不是,它只有第一个元素单独享用一字节,其他三个元素一起共用一字节,所以puc被结构体填充后,本身只有两个字节会被写入,后两个字节肯定是0,

然后第一个字节是2就是2了,第二个字节比较麻烦,首先ucData0给了3其实是越界了,1位的数字只能是0或1,所以11截断后只有1,同理ucData1给的4也是越界的,100截断后是00,只有5的101是正常的。填充序列是类似小端的低地址在低位,所以排列顺序是00 101 00 1。也就是0010 1001,

所以结果为02 29 00 00

三.枚举

枚举是一个被命名的整型常数的集合,枚举在日常生活中很常见,例如表示星期的SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY就是一个枚举。

枚举就是一个对象的所有可能取值的集合 

#include<stdio.h>
enum sex
{male,female,secret,
};

枚举的关键字是enum 在括号内部注意每个成员名后面要加逗号,同时别忘了括号外面的分号

枚举内部的成员被依次赋值为0,1,2

我们假如将female赋值为1,secret就被赋值为2,male赋值为0

3.1枚举的优点 

1.增加代码的可读性和可维护性

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

3. 防止了命名污染(封装)

4. 便于调试

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

enum Sex        //枚举的申明定义
{Male,        //枚举常量,默认值是0开始,一次递增1female,secret
};
enum Color
{RED=1,        //也可以手动赋值GREEN=2,BLUE=4
};
int main(){enum Sex a = Male;         //枚举顾名思义就是一一列举。enum Color b = RED;printf("%d %d %d\n", Male, female, secret);printf("%d %d %d\n", RED, GREEN, BLUE);
}

 

四.联合(共用体)

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

联合大小的计算 

  1. 联合的大小至少是最大成员的大小。
  2. 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍 
// 联合体/共用体  -  里面的成员同一时间只能用一个union Un
{char c;     // 1int i;     // 4
};union U
{short s[7]; // 14int i; // 4
};int main()
{union Un u = { 0 };printf("%d\n", sizeof(u)); // 输出 4// 下面三行输出同样的地址printf("%p\n", &u); printf("%p\n", &(u.c));printf("%p\n", &(u.i)); union U c = { 0 };printf("%d\n", sizeof(c)); // 输出 16 内存对齐了(最大对齐数4的倍数)printf("%p\n", &c); // 输出printf("%p\n", &(c.s)); // 输出printf("%p\n", &(c.i)); // 输出return 0;
}

 联合体、大小端结合


int check_sys()
{union J{char m;int n;};J s1;s1.n = 1;return s1.m;
}
int main()
{if (check_sys()){printf("小端\n");}else{printf("大端\n");}return 0;
}
int main()
{union{short k;char i[2];}*s, a;s = &a;s->i[0] = 0x39;s->i[1] = 0x38;printf("%x\n", a.k);return 0;
}

 union只有2字节,2字节的十六进制只有4位,所以答案CD排除。而位顺序类似小端,低地址在低处,所以39是低地址,在低位,38在高位,所以是3839

 以上就是我对【C语言】结构体的全部介绍了,身为初学者自知有很多不足,望各位大佬指点得以改正!!!感激不尽。

 

 

 

相关文章:

【C语言】进阶——结构体+枚举+联合

①前言&#xff1a; 在之前【C语言】初阶——结构体 &#xff0c;简单介绍了结构体。而C语言中结构体的内容还有更深层次的内容。 一.结构体 结构体(struct)是由一系列具有相同类型或不同类型的数据项构成的数据集合&#xff0c;这些数据项称为结构体的成员。 1.结构体的声明 …...

Socket编程基础(1)

目录 预备知识 socket通信的本质 认识TCP协议和UDP协议 网络字节序 socket编程流程 socket编程时常见的函数 服务端绑定 整数IP和字符串IP 客户端套接字的创建和绑定 预备知识 理解源IP和目的IP 源IP指的是发送数据包的主机的IP地址&#xff0c;目的IP指的是接收数据包…...

无线通信——Mesh自组网的由来

阴差阳错找到了一个工作&#xff0c;是做无线通信的&#xff0c;因为无线设备采用Mesh&#xff0c;还没怎么接触过&#xff0c;网上搜索下发现Mesh的使用场景不多&#xff0c;大部分都是用在家里路由器上面。所以写了片关于Mesh网的文档。Mesh网可应用在无网络区域的地方&#…...

LRU、LFU 内存淘汰算法的设计与实现

1、背景介绍 LRU、LFU都是内存管理淘汰算法&#xff0c;内存管理是计算机技术中重要的一环&#xff0c;也是多数操作系统中必备的模块。应用场景&#xff1a;假设 给定你一定内存空间&#xff0c;需要你维护一些缓存数据&#xff0c;LRU、LFU就是在内存已经满了的情况下&#…...

常用工具使用

ubuntu 1.1 ubuntu与windows 互相复制问题 方法一、 打开虚拟机 &#xff0c;点击上方导航栏 ‘虚拟机’ 查看VMware Tools是否安装&#xff0c;安装即可 方法二、 apt-get autoremove open-vm-tools apt-get install open-vm-tools apt-get install open-vm-tools-desktop…...

HashMap源码解析_jdk1.8(一)

HashMap解析 HashMap源码解析_jdk1.8&#xff08;一&#xff09;哈希常用数据结构查找/插入/删除性能比较。哈希冲突 HashMap的数据结构HashMap相关变量size和capacity HashMap源码解析_jdk1.8&#xff08;一&#xff09; 哈希 Hash&#xff0c;一般翻译做“散列”&#xff0…...

Android最好用的日志打印库(自动追踪日志代码位置)

给大家推荐一个自己写的日志打印的库&#xff0c;我愿称之为最强日志打印库&#xff1a;BytUtilLog Byt是Big一统的缩写&#xff0c;大一统日志打印库&#xff0c;哈哈&#xff01;搞个笑&#xff0c;很早就写好了&#xff0c;但后面忙起来就忘了写一篇文章推一下它了&#xff…...

面试官的哪些举动,暗示你通过了面试?

其实在求职过程中都会发现&#xff0c;求职者面试时间一般在20分钟以上&#xff0c;如果求职者较多&#xff0c;可能会在10分钟左右。(会在介绍以往工作上减少时间&#xff0c;内容主要以简单介绍&#xff0c;薪资要求&#xff0c;能力评价&#xff0c;到岗时间等等) 拿面试时…...

​旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著想象和世界一样宽广

​旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著想象和世界一样宽广...

Linux学习第19天:Linux并发与竞争实例: 没有规矩不成方圆

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 先说点题外话&#xff0c;上周参加行业年会&#xff0c;停更了一周。接下来的周五就要开启国庆中秋双节模式&#xff0c;所以有的时候&#xff0c;尤其是工作以后…...

Unity添加自定义菜单按钮

如果你想在Unity编辑器中添加自定义菜单按钮&#xff0c;你可以使用Unity的MenuSystem API。这是一个简单的示例&#xff1a; 首先需要引用using UnityEditor; using UnityEngine; using UnityEditor; 两个命名空间 然后在方法前添加 [MenuItem("原菜单名/自定义名…...

PHP8的类与对象的基本操作之类的实例化-PHP8知识详解

定义完类和方法后&#xff0c;并不是真正创建一个对象。类和对象可以描述为如下关系。类用来描述具有相同数据结构和特征的“一组对象”&#xff0c;“类”是“对象”的抽象&#xff0c;而“对象”是“类”的具体实例&#xff0c;即一个类中的对象具有相同的“型”&#xff0c;…...

C/S架构学习之TCP服务器

TCP服务器的实现流程&#xff1a;一、创建套接字&#xff08;socket函数&#xff09;&#xff1a;通信域选择IPV4网络协议、套接字类型选择流式&#xff1b; int sockfd socket(AF_INET,SOCK_STREAM,0); //通信域选择IPV4、套接字类型选择流式二、填充服务器的网络信息结构体&…...

基于微信小程序的线上教育课程付费商城(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

Linux基础指令(五)

目录 前言1. 打包和压缩1.1 是什么1.2 为什么1.3 怎么办&#xff1f; 2. zip & unzip3. tar 指令结语&#xff1a; 前言 欢迎各位伙伴来到学习 Linux 指令的 第五天&#xff01;&#xff01;&#xff01; 在上一篇文章 Linux基本指令(四) 当中&#xff0c;我们学习了 fin…...

C语言结构体的一些鲜为人知的小秘密

目录 一、结构体内存对齐规则&#xff1a; 1.1范例 1.2结构体内存对齐规则 1.3自定义默认对齐数 二、位段 2.1什么是位段 2.2位段的内存分配 2.3位段的不足 三、枚举和联合体 3.1枚举 3.1.1枚举类型的定义 3.1.2枚举类型的使用 3.2联合体 3.2.1联合体的定义 3.…...

kubernetes问题(一)-探究Pod被驱逐的原因及解决方法

1 k8s evicted是什么 k8s evicted是Kubernetes中的一个组件&#xff0c;主要用于处理Pod驱逐的情况。在Kubernetes中&#xff0c;当Node节点资源不够用时&#xff0c;为了保证整个集群的运行稳定&#xff0c;会按照一定的优先级和策略将其中的Pod驱逐出去。这时就需要一个组件…...

论文速览【序列模型 seq2seq】—— 【Ptr-Net】Pointer Networks

标题&#xff1a;Pointer Networks文章链接&#xff1a;Pointer Networks参考代码&#xff08;非官方&#xff09;&#xff1a;keon/pointer-networks发表&#xff1a;NIPS 2015领域&#xff1a;序列模型&#xff08;RNN seq2seq&#xff09;改进 / 深度学习解决组合优化问题【…...

Denoising diffusion implicit models 阅读笔记

Denoising diffusion probabilistic models (DDPMs)从马尔科夫链中采样生成样本&#xff0c;需要迭代多次&#xff0c;速度较慢。Denoising diffusion implicit models (DDIMs)的提出是为了加速采样过程&#xff0c;减少迭代的次数&#xff0c;并且要求DDIM可以复用DDPM训练的网…...

【Java 基础篇】Executors工厂类详解

在多线程编程中&#xff0c;线程池是一项重要的工具&#xff0c;它可以有效地管理和控制线程的生命周期&#xff0c;提高程序的性能和可维护性。Java提供了java.util.concurrent包来支持线程池的创建和管理&#xff0c;而Executors工厂类是其中的一部分&#xff0c;它提供了一些…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践

01技术背景与业务挑战 某短视频点播企业深耕国内用户市场&#xff0c;但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大&#xff0c;传统架构已较难满足当前企业发展的需求&#xff0c;企业面临着三重挑战&#xff1a; ① 业务&#xff1a;国内用户访问海外服…...

Python学习(8) ----- Python的类与对象

Python 中的类&#xff08;Class&#xff09;与对象&#xff08;Object&#xff09;是面向对象编程&#xff08;OOP&#xff09;的核心。我们可以通过“类是模板&#xff0c;对象是实例”来理解它们的关系。 &#x1f9f1; 一句话理解&#xff1a; 类就像“图纸”&#xff0c;对…...

FTXUI::Dom 模块

DOM 模块定义了分层的 FTXUI::Element 树&#xff0c;可用于构建复杂的终端界面&#xff0c;支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

Java中栈的多种实现类详解

Java中栈的多种实现类详解&#xff1a;Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...