可变参数列表

news2024/11/27 12:47:18

"多少人都,生来纯洁完美,心底从不染漆黑。"


        我们想要实现一个函数,这个函数的功能是返回一个整形的最大值。

        emm,似乎有那点味道。但这应用场景似乎很受限制,因为这个函数比较的有效区间,只能装下两个数…… 也许你会说,那我就增添几个参数不就得了?

         似乎问题,没有得到本质的解决。因为当你参数变多时,函数内的代码逻辑也得跟着更改。况且,如果遇到一个,你不知道会有多少个参数传入的场景,你又该如何选择参数个数的多少呢?

        也许你会说可以将数据存储在一个数组中,将数组作为参数进行传递。但,你同样不知道应该创建多大的数组来适应这种情况。

        难道我们对此就束手无策了吗?当然不是,C语言中提供了对这种不确定参数传入的解决方法

        “可变参数列表”。

——前言


一、 可变参数列表 

(1) 什么是可变参数

        在计算机程序设计,一个可变参数函数是指一个函数 "拥有不定引数" ,即是它接受一个可变数目的参数。简单来说,就是函数的参数个数可变,参数类型不定的函数。

        不同的编程语言对可变参数函数的支持有很大差异。

                                                                                                                            取自这里

        而可变参数的应用场景,前言的例子,也已经很恰当的演示了。

(2) 可变参数的使用

参数列表宏定义" 四板斧"

va_list arg: 其实就是定义一个char*类型,方便后续按照字节进行指针移动

va_start(arg,n(第一个参数)): 让指针指向(...)里的参数部分

va_arg(arg,类型): 从(...)取数据,并根据类型 朝后指向下一个参数 

va_end(arg): arg使用完毕,收尾工作。本质就是讲arg指向NULL

注意事项:

① 参数列表中至少有一个命名参数。
② 可变参数必须从头到尾逐个访问。如果你在访问了几个可变参数之后想半途终止,这是可以的,但是,如果你想一开始就访问参数列表中间的参数,那是不行的。

③ 参数列表中至少有一个命名参数。如果连一个命名参数都没有,就无法使用 va_start 。

④ 这些宏是无法直接判断实际存在参数的数量。
⑤ 如果在 va_arg 中指定了错误的类型,那么其后果是不可预测的。

        

        介绍了基本的可变参数的使用,我们来试试编写看。

         这样,我们就能够很轻松地使用这个可变参数列表了,完成了我们对“不定参数”下,求最大值的需求。


        仅仅三言两语讲解它的使用就截止了嘛?当然不是,因为从使用上来说,它确实很简单。可是要问你它底层是怎么实现的,指针是怎么移动的,如果传入的类型不是int呢?是字符型呢?是短整型呢?可变参数内部又是作何处理的?

二、可变参数原理

(1) 基本原理

        要弄清楚可变参数如何传参,如何让指针指向不同的值,来完成对参数的读取,我们一定得看看这 宏定义 " 四板斧"的底层是什么。

① va_list:

        

        va_list没有什么可以值得说的,因为它底层就是一个类型重定义的 char*指针。至于为什么是char*,因为在之后它好按照每字节进行偏移。

② va_start:

 

③ va_arg:

④ va_end:

         这个同va_list 一样没什么讲头,就是让创建的arg指针,指向空,防止野指针。

(2) 图示四板斧

        我知道,恐怕我就算将这四个宏定义函数讲得怎样绘声绘色,你也难以理解,更何况我讲得很烂。因此,以下根据图示看看这四个宏定义做了什么工作。

        可变参数是函数调用,而这里和函数栈帧的开辟以及参数的创建强相关,为此,在进行图示之前,你可以先看看下面的几个问题,看你是否真的掌握了函数栈帧的细节。

         根据上图,我们可以得出三个结论:

① 函数参数在函数调用前,就会在被压栈。

② 函数参数压栈的顺序是从右到左。

③ 每个参数的位置都是相对的,只要找到了第一个参数的位置,根据偏移量,就可以通过地址偏移的方式,获得其他参数值。

 

调用va_list 与 va_start;         

 

迭代va_arg:

置空va_end:
  

(3) 整形提升

        我们上面的实验是针对传入的是整型而言,现在我们来看看如果将传入的参数是" char"类型时,该函数还能否实现我们预期的功能?

         很显然,这些字符里最大的就是 'e',所对应的ASCII码为101,完成了我们预期的功能。可是,我们明明传入的是char类型诶,为什么按照 "int"类型的大小偏移指针,没有出错呢?

         唯一能给我们解释的,就是mov 与 movsx 。

        汇编语言数据传送指令MOV的变体。带符号扩展,并传送。简单来说,使用movsx汇编命令,让原本是char类型的变量,整型提升成了int!不管是char还是短整型都会被整型提升! 

        因此,如果我们看到以下代码,其实是不正确的。

 __crt_va_arg(arg, char);
 __crt_va_arg(arg, short);

        因此,为什么要按照4字节向上取整对齐? 本质上是为了 便于指针+偏移量的方式,按照字节读取每个地址处的参数值。

        

(4) 如何理解4字节对齐?

        这里的前提是,32位平台下,sizeof(int)大小是4,其他情况我们不考虑。

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

        单独这么看,似乎很难理解,为什么这个宏函数的功能能够实现4字节向上取整的功能。

第一步:        

第二步:

第三步:

         这就是大佬们的智慧,真的遥望而不可及。


总结:

        当然,对于可变参数列表的使用肯定是比原理更加得现实的,比较对于最后讲的4字节向上对齐怎么来的,是需要一定的数学基础和推理的,难度在这里摆着。

本篇到此结束,感谢你的阅读

祝你好运,向阳而生~

 

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

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

相关文章

Pycharm远程开发之全局pip,激活远程虚拟环境pip,以及pip的--user选项

前言 最近需要部署一下生成对抗网络的开发环境,我自己的笔记本没有带显卡,想到实验室的服务器有带显卡索性就用实验室服务器的环境开发,通过pycharm的远程开发功能连接到服务器,本来以为轻轻松松就可以开始写代码了,结…

springcloud整合nacos

1.订单服务(order) 1.1 安装nocas Nacos 快速开始 --注意:nacos 我的是 nacos-server-1.4.1.tar.gz 1.2 新建order-nacos 模块 1.3 修改pom文件 添加 nacos 依赖 1.4 配置文件添加 nacos 地址 1.5 创建启动类 使用 RestTemplate 方式调用服…

字符设备驱动内部实现

只要文件存在,就会有唯一对应的inode号,且相应的会存在一个struct inode结构体.,在应用层通过open()打开一个设备文件,会对应产生一个inode号,通过inode号可以找到文件的inode结构体,inode结构体…

中介者模式(二十一)

相信自己,请一定要相信自己 上一章简单介绍了观察者模式(二十), 如果没有看过, 请观看上一章 一. 中介者模式 引用 菜鸟教程里面中介者模式介绍: https://www.runoob.com/design-pattern/mediator-pattern.html 中介者模式(Mediator Pattern&#xff…

paddlespeech http服务解决输出无符号

1.前情提要 下载paddlespeech官网代码并运行http服务进行中文识别时,会发现选择某些模型(我用的是conformer_wenetspeech),是别的结果为一串文字,没有标点,效果如下: 经过调用padddlespeech相关…

【裸机开发】使用汇编清除 .bss 段

目录 1、为什么要清除 .bss 段 2、使用汇编清除 .bss 段 1、为什么要清除 .bss 段 .bss 段保存的是 未被初始化 或者 初始化为0 的全局/静态变量。在编译器看来,这些东西是多余的,实际并不会给他们分配空间。因此,编译生成目标文件的时候&…

38.SpringCloud—注册中心(eureka/nacos)、负载均衡Ribbon

目录 一、SpringCloud。 (1)认识微服务。 (1.1)单体架构与分布式架构(微服务)。 (1.2)微服务技术对比。 (1.3)SpringCloud。 (2&#xff09…

linux创建静态库

创建一个目录,比如今天是6月13号,就mkdir 0613(创建目录0613),然后cd 0613(进入0613目录) 1.创建C语言库函数文件myheight.c vi myhight.c 2.创建C语言函数文件myweight.c vi myweight.c 3.创建C语言函数文件age.c vi myage.c 4…

代码审计-Java项目JDBCMybatisHibernate注入预编译写法

文章目录 Javaweb-数据库操作-模式&写法&预编译等环境搭建JDBC 注入分析关于预编译 Mybatis 注入分析Hibernate 注入分析总结: Javaweb-代码审计SQL注入-INXEDU在线网校 Javaweb-数据库操作-模式&写法&预编译等 环境搭建 VulDemo审计源码百度云 在…

深入理解深度学习——Transformer:解码器(Decoder)部分

分类目录:《深入理解深度学习》总目录 相关文章: 注意力机制(Attention Mechanism):基础知识 注意力机制(Attention Mechanism):注意力汇聚与Nadaraya-Watson核回归 注意力机制&…

微信小程序分享到微信,公众号h5分享到微信,微信小程序跳转h5页面

一:微信小程序分享到微信 1:需求 分享微信小程序中某个详情页,可以分享到群,个人,朋友圈,好友点击分享页,能跳转到对应详情页阅读。 2:分析问题 如何实现分享?分享时如…

Nvidia 3060显卡 CUDA环境搭建(Ubuntu22.04+Nvidia 510+Cuda11.6+cudnn8.8)

写在前面 工作中遇到,简单整理理解不足小伙伴帮忙指正 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大…

【踩坑记录】STC8H8K64U硬件PWM使用小结

快速导航 写在前面库配置时钟配置GPIO配置定时器配置串口配置硬件PWM特殊功能同步功能 总结 写在前面 不出意外这是我第一次也是最后一次使用STC的芯片,写这篇博的目的纯粹记录下前段时间调试的痛苦经历,所有目前打算选或是已经开始调试这款芯片的朋友&…

Ubuntu16.04部署BEVformer 实时记录

一 配置依赖 a. Create a conda virtual environment and activate it. conda create -n open-mmlab python3.8 -y conda activate open-mmlabb. Install PyTorch and torchvision following the official instructions. pip install torch1.9.1cu111 torchvision0.10.1cu11…

【Linux】面试重点:死锁和生产消费模型原理

面试要点来了~ 文章目录 前言一、死锁的一系列问题二、生产者消费者模型原理总结 前言 上一篇的互斥量原理中我们讲解了锁的原理,我们知道每次线程申请锁的时候一旦申请成功这个线程自己就把锁带在自己身上了,这就保证了锁的原子性(因为只有…

备忘录模式(二十二)

相信自己,请一定要相信自己 上一章简单介绍了中介者模式(二十一), 如果没有看过, 请观看上一章 一. 备忘录模式 引用 菜鸟教程里面备忘录模式介绍: https://www.runoob.com/design-pattern/memento-pattern.html 备忘录模式(Memento Pattern&#xff…

基于Java单位人事管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍: ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精…

大面积无线WIFI覆盖 H3C WX3010E(AC+PoE三层交换机)+ H3C WA2620E、WA4320无线AP +华为USG6310S防火墙

一、适用场景: 1、跨复杂区域覆盖WIFI。支持多房间、多栋、多层复式楼、别墅、自建房的无线WIFI覆盖。 2、强大的漫游功能。楼上楼下移动使用WIFI时,需要支持WIFI的信号漫游,更换地理位置不掉线、不中断。 3、用户量或网络流量的负载均衡功…

IMX6ULL的官方SDK和官方BSP下载

买了块IMX6ULL的开发板,但是不想直接用开发板跟的程序,还有比如后面移植uboot和kernel的时候也想基于IMX6ULL官方的uboot和kernel做移植工作,所以自己先找一下怎么在官网下载这些东西。 1 官方SDK下载 百度搜索NXP官网,进去之后…

HotSpot虚拟机参数配置及优化

目录 一、JVM配置参数 二、GC回收日志分析 三、虚拟机性能监控和故障处理工具 1.命令工具 1):基础工具 2):性能监控和故障处理 2.可视化工具 四、JVM常出现问题 五、参考资料 一、JVM配置参数 HotSpot直到JDK9才提供统一的日志处理框架&#xff…