兰泽又多芳草,可变参数列表
Posted 乔乔家的龙女仆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了兰泽又多芳草,可变参数列表相关的知识,希望对你有一定的参考价值。
传统艺能😎
小编是大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】
乔乔的gitee代码库(打灰人 )欢迎访问,点我!
过渡区🤣
现在是北京时间13:15,期末考试结束,明天卷铺盖回家喽!yysy,算见识了嘛是卷翻天,博客之星20s没见就给降了一名,睡一觉起来各位都是一万多总分,泪,6 了下来。我放假了各位,键盘不烂我不睡好吧
正片开始👀
可变参数👏
可变参数是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 指针强转之后,此时就有了一个指针以一字节为单位,指向入栈的第一个有效元素。要想继续指向后面可变部分,就要继续向下移动四个字节,加上他本身大小就能移动到可变部分。
今天就先到这里,摸了家人们。
以上是关于兰泽又多芳草,可变参数列表的主要内容,如果未能解决你的问题,请参考以下文章