广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言进阶可变参数列表
  • 969
分享到

C语言进阶可变参数列表

2024-04-02 19:04:59 969人浏览 泡泡鱼
摘要

可变参数 可变参数是C语言提供的一种参数可变的机制,咱希望函数带有可变数量的参数,而不是预定义数量的参数。它允许咱定义一个函数,能根据具体的需求接受可变数量的参数,比如这种: int

可变参数

可变参数是C语言提供的一种参数可变的机制,咱希望函数带有可变数量的参数,而不是预定义数量的参数。它允许咱定义一个函数,能根据具体的需求接受可变数量的参数,比如这种:

int Max(int num,...)
{
 va_list arg;
 va_start(arg,num);
 int max = va_arg(arg,int);
 for(int i = 1;i<num;i++)
 {
 int sid = va_arg(arg,int);
 }
 if(sid > max)
 {
 max = sid;
 }
 va_end(arg);
 return max; 
}
int main()
{
int a = Max(5,1,2,3,4,5);
printf("%d\n",a);
return 0;
}

如上形式Max函数就用到了可变参数,注意!使用可变参数时,Max内首元素 ‘ 5 ’代表元素个数

在这里插入图片描述

那么问题来了,如果函数没有形式参数,可以给函数传递吗?答案是可以的,在C语言中,只要发生了函数调用并调用了参数,必定会形成临时变量;所谓临时拷贝(变量)的本质,也就是在栈帧内部形成的(从右向左形成临时拷贝(变量)).

宏观过程

va_list定义了可以访问可变参数部分的变量,他的本质是一个 char 类型指针。va_start 使 b 指向可变参数部分,va_end 是用来完成收尾工作的,本质就是将参数arg置为空,避免野指针。

掐头去尾,我们看看主体部分。首先 arg 指针先让我的数据入栈,我们打开反汇编能看到栈顶 esp 位置,再在内存窗口找到 esp 位置,就会看到这个经典的一幕,倒着入栈连着几个数据入栈是压在一起的,这种结构对我们查找元素就非常友好了。

在这里插入图片描述


宏观的框架就是我们传入的变量 num 就代表第一个参数 5,va_start 就是让 arg 原本指向5的 ,再让他指向有效部分,比如 1,根据指向 1 的起始地址, va_start 指向他的可变部分(去掉已指向的有效部分),具体如何实现见下文;最后 va_arg 就是根据类型 int ,从起始地址开始连续读取找到某一个元素,这样最终会把所需要的 max 的值读出来。

原理

可变参数列表对应的函数,最终调用也是函数调用,也要形成栈帧,栈帧形成前,临时变量会先入栈,根据咱之前总结的,参数位置都是相对固定的;在可变参数中 ,如果是短整型,一般都要进行整型提升,比如参数传入的是 char 类型,但实际传出的是 int 类型,这就是我们的 va_arg(arg,int)为什么是 int 而不是 char,所以在 va_arg 中指定了错误的类型,那结果无法预测。

要注意:
1.可变参数必须从头到尾逐个进行访问,如果你访问了几个可变参数后想半途而废,是可以做到的,但如果一开始就想访问中间某个元素的话,哒咩!
2.参数列表中至少有一个命名参数,如果连一个参数都没有,就没办法使用 va_start;
3.这些宏是没办法直接判断实际存在的参数数量的,也无法判断每个参数的类型

格局打开

#define _crt_va_start(ap,v)  (ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)
#define _crt_va_arg(ap,t)  (*(t*)((ap += _INTSIZEOF(t) - _INTSIZEOF(t))
#define _crt_va_start(ap)  (ap = (va_list)0)
)

谈完原理就要谈原理的原理,可变参数的几个宏就给出了他的运作原理,ap 就相当于 arg, v 就相当于变量 num,va_list 相当于 char *,这里 ADDRESS 相当于取地址,所以就是在对 char 指针强转之后,此时就有了一个指针以一字节为单位,指向入栈的第一个有效元素。要想继续指向后面可变部分,就要继续向下移动四个字节,加上他本身大小就能移动到可变部分。

第二个宏也是特别有意思,ap是va_arg(arg,int),t 是我们的类型—— int ,括号里的部分:(ap += _INTSIZEOF(t))其中 INTSIZEOF 计算了int 的大小,这里让 ap 先 += 四个字节,就让 ap 直接指向了下一个元素的位置,后面再减去 int 的大小让他又回到了第一个元素

在这里插入图片描述


注意减的过程并没有赋给 ap,ap指向的是 2,而整个表达式指向的是 4,(t) 将这个 char 类型指针强转成 int 类型指针再解引用,通过强制转换,提取出符合类型大小的数据。整个过程就是把第一个元素分离出来了。这个设计可谓非常优秀,不仅指针下移了,元素也访问了,属实美哉。

end宏很好理解,ap = 0了再强转成 char* ,他的实际意义就是将指针归0,避免野指针。

四字节对齐

INTSIZEOF 是如何实现的?我们将 INTSIZEOF 转到定义,下面这段宏在函数内部就开始进行使用了为什么还要进行四字节对齐呢?因为从首元素到第二个元素中间的空间是可以访问的,我不限制大小就有可能访问不到第二个元素,所以在形参被运用时除了发生整型提升还有就是四字节对齐。

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

比如我是个 char 类型,sizeof(char)+sizeof(4)-1 &~ (sizeof(4)-1)就是 4 &~ 3,0000……0100 & 1111……1100 = 4 , 如此就能实现以最小的方式向上四字节取整,完成四字节对齐。从可读性上讲,这是真的麻烦,我们其实直接写成(n+4-1)& -(4-1)也无妨,这种简洁版不香吗是吧。

今天就先到这里,摸了家人们,更多关于C语言可变参数列表的资料请关注编程网其它相关文章!

--结束END--

本文标题: C语言进阶可变参数列表

本文链接: https://www.lsjlt.com/news/139117.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言进阶可变参数列表
    可变参数 可变参数是C语言提供的一种参数可变的机制,咱希望函数带有可变数量的参数,而不是预定义数量的参数。它允许咱定义一个函数,能根据具体的需求接受可变数量的参数,比如这种: int...
    99+
    2022-11-13
  • C语言可变长的参数列表详解
    C语言可变长的参数列表 C语言可创建接收参数个数不确定的函数。如常用的标准库函数printf就是一个接收参数个数可变的函数。函数printf至少要接收一个字符串作为它的第一个实参。但...
    99+
    2022-11-12
  • C语言可变参数列表的用法与深度剖析
    目录前言一、可变参数列表是什么?二、怎么用可变参数列表三、对于宏的深度剖析隐式类型转换对两个函数的重新认知总结前言 可变参数列表,使用起来像是数组,学习过函数栈帧的话可以发现实际上他...
    99+
    2022-11-13
  • C语言可变参数函数详解
    目录C语言可变参数函数总结C语言可变参数函数 C 语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function)。这种函数需要固定数量的强制参数(manda...
    99+
    2022-11-12
  • C语言中可变参数如何使用
    C语言中可变参数如何使用,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、什么是可变参数我们在C语言编程中有时会遇到一些参数个数可变的函数,例如printf()...
    99+
    2023-06-17
  • C语言如何实现可变参数详解
    目录可变参数实现代码分析关键语句为什么内存地址难点优化总结可变参数 可变参数是指函数的参数的数据类型和数量都是不固定的。 printf函数的参数就是可变的。这个函数的原型是:int...
    99+
    2022-11-12
  • C语言中的可变参数怎么使用
    今天小编给大家分享一下C语言中的可变参数怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、什么是可变参数我们在C语言...
    99+
    2023-06-08
  • C语言的可变参数函数实现详解
    目录1、简介2、简单的使用方式总结1、简介 今天看到一个有趣的东西C语言的可变参数函数 众所周知,C语言的函数不能重载,那么你printf和scanf是怎么可以输入多个参数的 例如查...
    99+
    2022-11-12
  • C语言中可变参数的原理是什么
    C语言中可变参数的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。var_list可变参数介绍VA_LIST 是在C语言中解决变参问题的一组宏,原型:typedef&n...
    99+
    2023-06-15
  • C语言可变参数与函数参数的内存对齐详解
    目录什么是可变参数?使用可变参数函数参数的内存对齐总结什么是可变参数? 有时,您可能会碰到这样的情况,您希望函数带有可变数量的参数,而不是预定义数量的参数。 C 语言为这种情况提供了...
    99+
    2022-11-13
  • 【C++】C++11语法 ~ 可变参数模板
    🌈欢迎来到C++专栏~可变参数模板 ...
    99+
    2023-08-17
    c++ java 开发语言
  • java可变参数列表zm 填充数组
    这篇文章给大家分享的是有关java可变参数列表zm 填充数组的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基于Java的实现了We...
    99+
    2023-06-14
  • C语言数据结构顺序表的进阶讲解
    目录前言一、顺序表的构造VS功能1.顺序表的构造2.接口实现(功能)二、功能具体分析1.初始化2.销毁3.检查size与capacity是否溢出4.尾增功能(实现)5.打印三、实现具...
    99+
    2022-11-13
  • C语言可变参数与内存管理超详细讲解
    目录概述动态分配内存重新调整内存的大小和释放内存概述 有时,您可能会碰到这样的情况,您希望函数带有可变数量的参数,而不是预定义数量的参数。C 语言为这种情况提供了一个解决方案,它允许...
    99+
    2023-01-02
    C语言可变参数 C语言内存管理
  • C语言数据结构进阶之栈和队列的实现
    目录栈的实现:一、栈的概念和性质二、栈的实现思路三、栈的相关变量内存布局图四、栈的初始化和销毁五、栈的接口实现:1.入栈2.出栈3.获取栈顶的数据4.获取栈的元素个数5.判断栈是否为...
    99+
    2022-11-12
  • Go语言中函数可变参数(VariadicParameter)详解
    目录基本语法示例一:函数中获取可变参数示例二:将切片传给可变参数示例三:多参数基本语法 在Python中,在函数参数不确定数量的情况下,可以使用如下方式动态在函数内获取参数,args...
    99+
    2022-11-13
  • C语言中变参函数传参的实现示例
    目录背景引入问题分析指针大小参数位置排布解决问题额外的测试总结参考资料背景引入 近期在看一本书,叫做《嵌入式C语言自我修养》,写的内容对我帮助很大,是一本好书。在第6章,GNU C编...
    99+
    2022-11-12
  • C语言 指针数组进阶详解
    目录指针与数组中的sizeof与strlensizeofstrlen数组名1、一维数组整型数组字符数组指针数组2、二维数组指针笔试题 笔试题1笔试题2笔试题3笔试题4笔试题...
    99+
    2022-11-13
  • PHP函数可变参数列表的具体实现方法
    这篇文章将为大家详细讲解有关PHP函数可变参数列表的具体实现方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。也许对于PHP初级程序员来说,对于PHP函数并不能完全熟练的掌握。我们今天为大家...
    99+
    2023-06-17
  • C++11中的可变参数模板/lambda表达式
    目录1.可变参数模板递归函数方式展开参数包逗号表达式展开参数包2.lambda表达式先来看看lambda表达式的例子:lambda表达式语法1.可变参数模板 C++11的新特性可变参...
    99+
    2023-03-24
    C++11 lambda表达式 C++11 可变参数模板
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作