自定义类型结构体(下)

目录

  • 结构体传参
  • 结构体实现位段
    • 什么是位段
    • 位段的内存分配
      • 位段的跨平台问题
      • 总结:
    • 位段的应用
    • 位段使用的注意事项**

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐓🏀 python

结构体传参

struct S
{int data[1000];int num;
};
struct S s = { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct S s)
{printf("%d\n", s.num);
}
int main()
{print1(s); //传结构体return 0;
}
struct S
{int data[1000];int num;
};
//结构体地址传参
void print2(struct S* ps)
{printf("%d\n", ps->num);
}
int main()
{print2(&s); //传地址return 0;
}

上面的 print1 和 print2 函数哪个好些?
答案是:首选print2函数

原因:
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降

结论:
结构体传参的时候,要传结构体的地址

结构体实现位段

什么是位段

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

1:位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以选择其他类型

2: 位段的成员名后边有一个冒号和一个数字

比如:

struct A
{int _a : 2;//_a占用2个比特位的空间int _b : 5;//_b占用5个比特位的空间int _c : 10;//_c占用10个比特位的空间int _d : 30;//_d占用30个比特位的空间
};

A就是一个位段类型。
对_a来说既然是占用了2个比特位的空间,那么a的取值范围我们也是可以确定的,用二进制来表示就是00 01 10 11,也就是说a只能是0 1 2 3这四种情况

但如果我们没有用位段的方式来表示int _a的话,那么_a就会占32个比特位,这样所占内存就比较大了,如果我们知道结构体的某一些成员实际上用不了32个比特位的话,我们就可以用位段的方式来表示那个成员

我们来看一下下面的代码

struct A
{int _a : 2;//_a占用2个比特位的空间int _b : 5;//_b占用5个比特位的空间int _c : 10;//_c占用10个比特位的空间int _d : 30;//_d占用30个比特位的空间
};
struct B
{int _a ;int _b ;int _c ;int _d ; 
};
int main()
{
printf("%d\n", sizeof(struct A));
printf("%d\n", sizeof(struct B)); 
}

在这里插入图片描述
通过位段我们就大大的缩小了结构体所占内存,所以位段在使用时一定要知道每个成员最大所需要占用的多少个比特位

位段的内存分配

1:位段的成员可以是 int unsigned int signed int 或者是 char 等类型

2:位段的空间上是按照需要以4个字节( int )或者1个字节 (char )的方式来开辟的(就是如果是int类型,每次申请开辟就是4个字节4个字节的开辟,而如果是char类型,每次申请开辟就是1个字节1个字节的开辟)

3:位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

我们还是之前的例子

struct A
{int _a : 2;//_a占用2个比特位的空间int _b : 5;//_b占用5个比特位的空间int _c : 10;//_c占用10个比特位的空间int _d : 30;//_d占用30个比特位的空间
};
struct B
{int _a ;int _b ;int _c ;int _d ; 
};
int main()
{
printf("%d\n", sizeof(struct A));
printf("%d\n", sizeof(struct B)); 
}

int 大小为4个字节也就是32个比特位,因为我们已知a只占两个比特位,但是a应该是存储在哪两个比特位,这其实是不确定的
在这里插入图片描述

并且对于int b int c…在存储时是否会占用之前的32个比特位呢?
其实也是不确定的

在这里插入图片描述
因为不同的编译器具体的操作是不确定的,但是我们可以针对某一个编译器来研究一下
我们举个例子:

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;

在这里插入图片描述
我们可以看到struct S所占大小为3个字节,我们来分析一下

因为char类型是占一个字节也就是8个比特位,所以在给a开辟内存的时候会先开辟8个比特位给a

但由于a只占用3个比特位(这里需要注意因为a的2进制表示是1010,注意我们规定a只占3个比特位,所以我们需要丢失数据),因此a存入的只是010

而在VS中我们是可以用到a空出来没用的其余5个比特位,因为b只占4个比特位,我们就可以将b较完整的存入

而剩下的一个比特位c是否会用到呢?
我们假设c需要用到
在这里插入图片描述

这样的话结果就如图,红色的是c所占的内存,显然这样的话结果应该是2个字节,这与之前运行结果是不同的,因此a和b剩下的一个比特位c是没有用到的

如果c没有用到的话那么真实情况应该是这样的
在这里插入图片描述

c用剩下的3个比特位也不够d去用和之前的情况是一样的,所以d会重新开辟一个空间,这样的话内存大小就是3个字节

我们用16进制来表示
在这里插入图片描述

我们通过调试得出结果如图
在这里插入图片描述
结果确实也是这样

位段的跨平台问题

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

2:位段中最大位的数目不能确定。(16位机器最大16)(即早期整形的大小是2个字节=16个比特位),32位机器最大32(整形的大小是4个字节=32个比特位),写成27,在16位机器会出问题,所以我们位段中设置的大小是不能超过成员自身最大的位的(即int类型如果是32个比特位,我们就不能设置成33个比特位)。

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

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

总结:

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

位段的应用

下图是网络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要几个bit位就能描述,这里使用位段,能够实现想要的效果,也节省了空间,这样网络传输的数据报大小也会较小⼀些,对网络的畅通是有帮助的
在这里插入图片描述

位段使用的注意事项**

位段的几个成员共用同一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。

内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的。

所以不能对位段的成员使用&操作符,这样就不能使用scanf直接给位段的成员输入值,只能是先输入放在一个变量中,然后赋值给位段的成员

struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{struct A sa = { 0 };scanf("%d", &sa._b);//这是错误的//正确的⽰范int b = 0;scanf("%d", &b);sa._b = b;return 0;
}

在这里插入图片描述

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

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

相关文章

应聘遇到性格测试,怎么做才能通过?

本人xxx专业,最近找工作,总会做到性格测试题,好几次了,做完性格测试就没消息了,已经疯了,直接给跪了,完全找不到套路,都快怀疑人生了。所以想问一下,像这样公司的性格测试…

什么是TCY油封?

机械由无数组件协同工作以确保平稳运行,其中一种不可或缺的部件是油封,特别是TCY油封。本文旨在阐明TCY油封的应用、其重要性以及它们如何提高机械的整体效率。 TCY油封主要用于轴密封。轴是一种旋转机器元件,横截面通常为圆形,用…

Microsoft 365 管理自动化

Microsoft 365 服务被大多数组织广泛使用,每天生成的数据量巨大。解决 Microsoft 365 中的问题可能非常困难,并且使用多个管理中心来保护组织变得复杂。本机控制台还缺少某些批量管理任务、全面的审计报告和基于角色的精细访问控制。 Microsoft 360 管理…

c++获取和设置环境变量

这个功能非常常用,但是容易忘记,这里做个记录。 注意,设置的环境变量只在当前进程中生效,所以在电脑中的环境变量设置区域看不到。 std::string env getenv("PATH");env "X:\\envtest";std::string newEnv…

【机器学习】几种常用的机器学习调参方法

在机器学习中,模型的性能往往受到模型的超参数、数据的质量、特征选择等因素影响。其中,模型的超参数调整是模型优化中最重要的环节之一。超参数(Hyperparameters)在机器学习算法中需要人为设定,它们不能直接从训练数据…

0基础学习PyFlink——事件时间和运行时间的窗口

大纲 定制策略运行策略Reduce完整代码滑动窗口案例参考资料 在 《0基础学习PyFlink——时间滚动窗口(Tumbling Time Windows)》一文中,我们使用的是运行时间(Tumbling ProcessingTimeWindows)作为窗口的参考时间: reducedkeyed.window(TumblingProcess…

国际测试委员会BenchCouncil首发“开源系统杰出成果榜” 百度飞桨上榜

📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于恒川的日常汇报系列,大家有兴趣的可以看一看 📘相关专栏C语言初阶、C…

关于pytorch张量维度转换及张量运算

关于pytorch张量维度转换大全 1 tensor.view()2 tensor.reshape()3 tensor.squeeze()和tensor.unsqueeze()3.1 tensor.squeeze() 降维3.2 tensor.unsqueeze(idx)升维 4 tensor.permute()5 torch.cat([a,b],dim)6 torch.stack()7 torch.chunk()和torch.split()8 与tensor相乘运算…

RESTful接口实现与测试

目录标题 是什么?设计风格HTTP协议四种传参方式常用注解RequestBody与ResponseBodyRequestMapping注解RestController与ControllerPathVariable 与RequestParam 接受复杂嵌套对象参数Http数据转换的原理自定义HttpMessageConverter统一规划接口响应的数据格式实战&a…

为什么重写 redisTemplate

为什么重写 redisTemplate 1.安装 redis 上传 redis 的安装包tar -xvf redis-5.0.7.tar.gzyum -y install gcc-cmakemake PREFIX/soft/redis installcd /soft/redis/bin./redis-server redis.conf 2. 集成 redisTemplate maven 依赖 <dependency><groupId>org…

详解Java经典数据结构——HashMap

Java 的 HashMap 是一个常用的基于哈希表的数据结构&#xff0c;它实现了 Map 接口&#xff0c;可以存储键值对。下面我们进行详细介绍&#xff1a; 基本结构&#xff1a;HashMap 底层是基于哈希表来实现的&#xff0c;每次插入一个键值对时&#xff0c;会先对该键进行 Hash 运…

Locust:可能是一款最被低估的压测工具

01、Locust介绍 开源性能测试工具https://www.locust.io/&#xff0c;基于Python的性能压测工具&#xff0c;使用Python代码来定义用户行为&#xff0c;模拟百万计的并发用户访问。每个测试用户的行为由您定义&#xff0c;并且通过Web UI实时监控聚集过程。 压力发生器作为性…

本地部署Jellyfin影音服务器并实现远程访问影音库

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

【Python3】【力扣题】219. 存在重复元素 II

【力扣题】题目描述&#xff1a; 【Python3】代码&#xff1a; 1、解题思路&#xff1a;哈希表。遍历每个元素&#xff0c;将元素及下标添加到字典&#xff0c;若当前元素已在字典中且下标之间距离k&#xff0c;则存在重复元素。 知识点&#xff1a;{}&#xff1a;创建空字典…

【OpenCV实现图像梯度,Canny边缘检测】

文章目录 概要图像梯度Canny边缘检测小结 概要 OpenCV中&#xff0c;可以使用各种函数实现图像梯度和Canny边缘检测&#xff0c;这些操作对于图像处理和分析非常重要。 图像梯度通常用于寻找图像中的边缘和轮廓。在OpenCV中&#xff0c;可以使用cv2.Sobel()函数计算图像的梯度…

都是80m²小户型,凭啥她家那么好看!福州中宅装饰,福州装修

杨桥新苑 本案来自杨桥新苑的住宅&#xff0c; 质朴弥漫在80㎡的小家&#xff0c; 自然淡雅的木纹&#xff0c;精炼的玄关隔断&#xff0c; 简约的设计里传达着中式的静谧风雅&#xff0c; 简练的空间加入中国元素&#xff0c; 让人从进门开始就沾染一丝艺术气息。 风格&a…

瑞禧生物分享~今天是 碲化银粉体 Ag2Te CAS:12002-99-2

碲化银粉体 Ag2Te CAS&#xff1a;12002-99-2 纯度&#xff1a;99% 仅用于科研 储藏条件&#xff1a;冷藏-20℃ 简介&#xff1a;碲化银是一种无机化合物&#xff0c;化学式是Ag2Te。它是一种单斜晶体&#xff0c;并以矿物的形式存在于自然界中。化学计量的碲化银具有n型半导…

AI:50-基于深度学习的柑橘类水果分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

【Linux】Nignx及负载均衡动静分离

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《微信小程序开发实战》。&#x1f3af;&#x1f3a…

系列四、全局配置文件mybatis-config.xml

一、全局配置文件中的属性 mybatis全局配置中的文件非常多&#xff0c;主要有如下几个&#xff1a; properties&#xff08;属性&#xff09;settings&#xff08;全局配置参数&#xff09;typeAliases&#xff08;类型别名&#xff09;typeHandlers&#xff08;类型处理器&am…