ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C语言可变参数函数_初探

C语言可变参数函数_初探 一、什么是可变参数函数C语言允许定义参数数量可变的函数这称为可变参数函数variadic function。这种函数需要固定数量的强制参数后面是数量可变的可选参数。其中强制参数必须至少一个可选参数数量可变类型可变可选参数的数量由强制参数的值决定或由用来定义可选参数列表的特殊值决定。其实我们早就接触过可变参数函数了C 语言中最常用的可变参数函数例子是 printf和 scanf。这两个函数都有一个强制参数即格式化字符串。格式化字符串中的转换修饰符决定了可选参数的数量和类型。是吧printf中可以有自定义个%d没毛病可变参数函数的参数列表的格式是强制性参数在前后面跟着一个逗号和省略号…这个省略号代表可选参数。比如int fun(int, …) (我随便举的例子啊)二、可变参数函数的实现 1、问题引入我们先来思考这样一个问题作为本节的引入如果我们要预先写一个可变参数的累加求和函数其强制参数类型为int用它来表示我们一共要传入多少个可变参数。于是我们大概可以有这么一个框架double getSum(int NumofPara, ...) { int i 0; double sum 0.0; for( i 0; i NumofPara; i ) { sum ?? } }发现什么问题没有由于已经知道要传入多少个可变参数所以求和思路就是for循环遍历NumofPara次每次都把sum加上一个可变参数。思路很清晰没毛病。但是问题来了。由于是可变参数我们无法提前得知可变参量的名字也就没法访问这些可变参数。你参数列表里都是一串省略号了你怎么可能提前知道变量名所以自然而然也无法表示、无法访问这些变量了2、实现思路为了解决上述问题C语言规定当编写可变参数函数时必须用 va_list 类型定义参数指针以获取可选参数。可变参数函数要获取可选参数时必须通过一个类型为 va_list 的对象来进行访问它包含了参数信息。这种类型的对象也称为参数指针argument pointer它包含了栈中至少一个参数的位置。可以使用这个参数指针从一个可选参数移动到下一个可选参数由此函数就可以获取所有的可选参数。va_list 类型被定义在头文件 stdarg.h 中。这么说可能太过官方太抽象了。我们来举个例子。假设我们有一个可变参数函数getSum(int NumofPara, …)然后现在我们代入具体值比如getSum(3, 7, 8, 9)通过上面的介绍我们知道第一个3是强制参数表明后面跟了3个可变参量而后面的7、8、9则为具体的可变参量。根据C语言的要求我们需要在getSum(int NumofPara, …)函数中定义一个va_list类型的指针。然后它是怎么实现“访问、获取可选参数”的呢C语言里是这样实现的通过某种机制等会儿会讲让强制参数和可选参数在内存中以连续的方式存放强制参数在前同时让va_list指针指向最后一个强制参数即第一个可选参数前的强制参数。然后通过另一种机制每次访问va_list所指的参量之后指针自动向后移位。进而当下一次再访问va_list的时候访问的就是下一位的值。这样就可以访问各个可变参数了。大概就是这样了讲得太接地气了。3、具体实现函数那么C语言又是怎么实现上面提到的这些机制的呢由此引入两个函数。void va_start(va_list argptr, lastparam);是va_list指针的初始化函数用来初始化指针也就是实现让其“先指向最后一个强制参数”的功能。于是自然而然的该函数的第一个参数是一个va_list 类型的指针第二个参数是可变参数函数中最后一个强制参数即第一个可选参数前的强制参数。va_start函数中va_list进行初始化指针指向末尾的强制参数。va_start结束后初始化完成指针自动移位到下一个参数即第一个可变参数。虽然感觉有点奇怪那么怎么访问va_list指针当前指向的可变参数呢引出第二个函数type va_arg(va_list argptr, type);其第一个参数是已经初始化完成的va_list指针第二个参数则为可变参数的类型返回的参数就是当前va_list指针所指的可变参数所以类型也跟传入的可变参数类型相同。每一次通过va_arg函数访问完一次参数后va_list指针会自动移位到下一位。C语言还规定当不再需要使用参数指针时必须调用宏 va_end来终结该指针其实说白了就是释放内存。如果想使用宏 va_start 或者宏 va_copy 来重新初始化一个之前用过的参数指针也必须先调用宏 va_end4、具体实现示例好了说了这么多我们通过完善之前写了一半的getSum函数来具体了解一下可能就会豁然开朗明明白白了double getSum(int NumofPara, ...) { int i 0; //用于for循环 double sum 0.0; //用于求和 va_list pointer; //新建一个va_list类型的指针 va_start(pointer, NumofPara); //初始化指针指针指向确定 for( i 0; i NumofPara; i ) { sum va_arg(pointer, double); //通过va_arg函数来访问可变参数返回类型为double } //同时每次va_arg函数结束后va_list指针指向下一位 va_end(pointer); //终结指针释放内存 return sum; //P.S. 有个问题要注意一下在main函数里调用的时候应该写成getSum(3, 7.0, 8.0, 9.0)否则得到的可能是0。 }接下来简单补充一下上面提到的所谓“机制”它的实现原理利用了内存的压栈技术将参数压入push栈内使用时再逐个从栈里pop出来需要注意的是压栈的顺序是从最右边参数开始的再向左逐个压入根据栈的原理在取参数时就从第一个可变参数开始了。在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减。所以取的时候就是从低到高也就是上面草图中从左到右从3到7到8到9三、不小心写多了一个标题上面说得比较粗糙可能有一些地方说错了。里面具体原理我也还没去深究。以后吧。参考资料C语言可变参数函数【干货】C语言可变参数C语言可变参数列表知识总结C语言中可变参数的使用方法基于本文知识点下一次再来追补一些关于vsprintf函数的知识点。dybf.ybt009.Comdyyw.ybt009.Comdypt.ybt009.Comdyywz.ybt009.Comdyksz.ybt009.Comksyw.ybt009.Comkspt.ybt009.Comkswz.ybt009.Comksywz.ybt009.Comkszz.ybt009.Comksdz.ybt009.Comksfs.ybt009.Comkspl.ybt009.Comkmbd.ybt009.Comkmzz.ybt009.Comkmxd.ybt009.Comkmpt.ybt009.Comkmdj.ybt009.Comkmwz.ybt009.Comdyfs.ybt009.Comdyfx.ybt009.Comdyfw.ybt009.Comdydz.ybt009.Comdypl.ybt009.Comdyzz.ybt009.Comdyxd.ybt009.Comdywz.ybt009.Comdyzx.ybt009.Comdyzb.ybt009.Comdyrq.ybt009.Comdyll.ybt009.Comdysp.ybt009.Comxhsdz.ybt009.Comxhsfs.ybt009.Comxhsyw.ybt009.Comxhspt.ybt009.Comxhsxd.ybt009.Comwbyw.ybt009.Comwbfs.ybt009.Comwbpt.ybt009.Comywpt.ybt009.Comywwz.ybt009.Comywxd.ybt009.Comywzz.ybt009.Comzzpt.ybt009.Comzzxd.ybt009.Comzzsc.ybt009.Comfspt.ybt009.Comfsxd.ybt009.Comfsyw.ybt009.Comdzpt.ybt009.Comdzxd.ybt009.Comdzyw.ybt009.Combfpt.ybt009.Combfxd.ybt009.Combfyw.ybt009.Complpt.ybt009.Complyw.ybt009.Comrqpt.ybt009.Comrqyw.ybt009.Comzbpt.ybt009.Comzbyw.ybt009.Comdygm.ybt009.Comdycs.ybt009.Comdyjr.ybt009.Comdyjy.ybt009.Comdyqd.ybt009.Comdygz.ybt009.Comdyxh.ybt009.Comdyfx.ybt009.Comdyzr.ybt009.Comdyhx.ybt009.Comdyhq.ybt009.Comdyjr.ybt009.Comdyss.ybt009.Comdyjm.ybt009.Comdysh.ybt009.Comdyhd.ybt009.Comdyhy.ybt009.Comdyjg.ybt009.Comdyzs.ybt009.Comdyfw.ybt009.Comksgm.ybt009.Comkscs.ybt009.Comksjm.ybt009.Comksqd.ybt009.Comksgz.ybt009.Comksxh.ybt009.Comksfs.ybt009.Comksdz.ybt009.Comkspl.ybt009.Comksbf.ybt009.Comksll.ybt009.Comksrq.ybt009.Comkszb.ybt009.Comkssp.ybt009.Comkszz.ybt009.Comksxd.ybt009.Comkspt.ybt009.Comkswz.ybt009.Comksfw.ybt009.Comkszx.ybt009.Comkmfw.ybt009.Comkmzx.ybt009.Comkmrk.ybt009.Comkmgs.ybt009.Comkmwd.ybt009.Comkmqd.ybt009.Comkmpt.ybt009.Comkmzz.ybt009.Comkmxd.ybt009.Comkmfw.ybt009.Comkmhy.ybt009.Comxhspt.ybt009.Comxhswz.ybt009.Comxhszz.ybt009.Comxhsxd.ybt009.Comxhsfw.ybt009.Comxhsfx.ybt009.Comxhstz.ybt009.Comxhsgz.ybt009.Comwbyw.ybt009.Comwbpt.ybt009.Comwbfs.ybt009.Comwbxd.ybt009.Comwbzz.ybt009.Comywfw.ybt009.Comywpt.ybt009.Comywwz.ybt009.Comywxd.ybt009.Comywzz.ybt009.Comywsc.ybt009.Comzzpt.ybt009.Comzzxd.ybt009.Comzzsc.ybt009.Comzzfw.ybt009.Comzzyw.ybt009.Comfspt.ybt009.Comfsxd.ybt009.Comfsyw.ybt009.Comfszz.ybt009.Comdzpt.ybt009.Comdzxd.ybt009.Comdzyw.ybt009.Comdzzz.ybt009.Combfpt.ybt009.Combfxd.ybt009.Combfyw.ybt009.Complpt.ybt009.Complxd.ybt009.Complyw.ybt009.Comrqpt.ybt009.Comrqxd.ybt009.Comrqyw.ybt009.Comzbpt.ybt009.Comzbxd.ybt009.Comzbyw.ybt009.Comdybs.ybt009.Comdygl.ybt009.Comdytz.ybt009.Comdytr.ybt009.Comdytl.ybt009.Comdyty.ybt009.Comdytw.ybt009.Comdylt.ybt009.Comdyrl.ybt009.Comdyre.ybt009.Comdyss.ybt009.Comdyfx.ybt009.Comdyfxw.ybt009.Comdygz.ybt009.Comdygzpt.ybt009.Comdygzxd.ybt009.Comdygzfw.ybt009.Comdyzf.ybt009.Comdyzs.ybt009.Comdyzt.ybt009.Comdyhh.ybt009.Comdyhm.ybt009.Comdyzr.ybt009.Comdyzx.ybt009.Comdyxh.ybt009.Comdyzb.ybt009.Comdyzbpt.ybt009.Comdyzbyw.ybt009.Comdyzbrq.ybt009.Comdyzbxd.ybt009.Comdyzbzz.ybt009.Comdyrq.ybt009.Comdyrqpt.ybt009.Comdyrqyw.ybt009.Comdyrqxd.ybt009.Comkszb.ybt009.Comkszbpt.ybt009.Comkszbyw.ybt009.Comkszbrq.ybt009.Comksrq.ybt009.Comksrqpt.ybt009.Comksrqyw.ybt009.Comksrqxd.ybt009.Comksll.ybt009.Comksllt.ybt009.Comksllyw.ybt009.Comksllpt.ybt009.Comksbf.ybt009.Comksbfpt.ybt009.Comksbfyw.ybt009.Comksbfxd.ybt009.Comkswz.ybt009.Comkspt.ybt009.Comksfw.ybt009.Comkszx.ybt009.Comksqd.ybt009.Comksdzpt.ybt009.Comksfspt.ybt009.Comxhs.ybt009.Comxhswz.ybt009.Comxhspt.ybt009.Comxhsfw.ybt009.Comxhsxd.ybt009.Comxhszz.ybt009.Comxhsyw.ybt009.Comxhsfs.ybt009.Comxhsdz.ybt009.Comkmyw.ybt009.Comkmpt.ybt009.Comkmwz.ybt009.Comkmzz.ybt009.Comkmxd.ybt009.Comkmfw.ybt009.Comkmrz.ybt009.Comkmrzpt.ybt009.Comkmgs.ybt009.Comkmqd.ybt009.Comdykm.ybt009.Comdykmpt.ybt009.Comdykmzz.ybt009.Comdykmxd.ybt009.Comdykmyw.ybt009.Comdykmdj.ybt009.Comdykmdj.ybt009.Comdykmwz.ybt009.Comdykmfw.ybt009.Comdydj.ybt009.Comdydjpt.ybt009.Comdydjyw.ybt009.Comdydjxd.ybt009.Comdydjfw.ybt009.Comdyzdj.ybt009.Comdyzdjpt.ybt009.Comdybz.ybt009.Comdybzpt.ybt009.Comdybzxd.ybt009.Comdybzfw.ybt009.Comdyta.ybt009.Comdytapt.ybt009.Comdytou.ybt009.Comdytt.ybt009.Comdytl.ybt009.Comdytlyw.ybt009.Comdyqc.ybt009.Comdyqcyw.ybt009.Comdyqctp.ybt009.Comdyqczf.ybt009.Com
返回列表