看山是山,看山不是山,最终看山才是山,并且是无穷的山峦。当我们学习一门技术的时候,起初是先模仿,但是最终是为了超越,也就是得到秘籍,看到本质。

于是,今天来继续看可变参数,我们来分析这个过程,代码如下:

声明int add (int num,...);...会说明是个可变函数,这样子编译器在编译遇到的函数的地方,就知道自动解析,依据传入的参数,直接进行进栈,从而不需要报错。

我们默认的函数,如果声明是两个参数,调用的是三个参数的话,最终会出错,会提示你找不到实现体。

声明完了后,实现函数,然后我们在使用的地方,直接传入多个参数,就不会出问题。

我们这里要看下add里面的具体实现,第一个参数我们利用这个值,用来判定长度,循环的结束点。

然后使用va_start 来卡找到第一个参数的地址,我这节画个图,大家就能理解了。再一个你也就明白了,为什么是int add(int num,...);而不是int add(...); 因为如果是这个,你实现的时候,就没法定位到起始地址,导致你无法解析后续的参数,这个明白了吧。

所以,编译时候,系统会提示错误,规定...参数前面必须有一个有名参数,否则系统编译的时候,你在实现体里面,无法做处理。这里就是 va_start(valist,num);

然后我们使用va_arg 去获取后续的参数,第一个是起始地址,第二个是后面紧跟着的数据,该以哪个大小去解析。我们这里是int,都是这个尺寸,所以用了循环。

在printf里面,使用的是%s ,%f这类处理,依据这个会变化。

使用完成后,就可以用va_end来结束指针。

我们如果把调用地方改成add(5,a,b);最终能输出出来结果,但是非常乱,原因很简单,这里的第一个参数5,让遍历寻找了栈上面的一些脏数据,导致结果未知。

我们如果把int b=6改成float b=6;会发生什么神奇的现象呢?出现了神奇的结果,原因很简单,float 进入栈的时候,占用的空间比int大,但是我们执行的时候,用了int大小去解析了这个数据,导致出现问题。

我们来看下如何修正这个问题,就需要格式化处理了,第一个参数,我们把它调整下,变成char *format,我们把代码改成这个,

为什么这里有float变为了double,主要是方便系统进行处理,升级后你 解析的时候,就要用double去解析,否则的话你处理完数据,ap指针就没有指到下一个位置,导致出错。

不过这个问题现在你不需要担心,如果你没有写对,系统会在编译时候提醒你,直接系统报错,让你去修改的。

这样子看下来,是不是觉得可变参数也没多神奇了?简单说下就是编译器支持...让函数参数可变,同时保留一个有名参数,让实现体可以用这个去定位到起始位置,然后进行遍历解析,完成逻辑处理。

我们把这个再抽象一层,简单来说,就是一组数据约束,存放在一起,然后我们依据一个格式化参数,对这个数据进行解析处理。当你看到这个的时候,就突然明白,协议的概念。

协议就是约定,约定双方同时遵循一个规则,同时遵守,就是协议。TCP/IP协议,ELF文件解析协议。

当你抽象到这里,基本上就大彻大悟,一切处理都是协议头 数据( 校验)。

在今天最后,我们来看下反编译后的代码,就明白了第一个参数的地址的意义,我这里用的int b=6;原因是如果是float的话,指令会比较复杂,不方便我们学习。

这里可以看到,我们地参数是 %d,%d  a b  这三个,在汇编代码中,可以看到,

rbp-0x8 放的是b的值,6

rbp-0xc 放的是a的值,5

rbp-0x14,放着一个地址4007ec,这地方就是%d,%d 常量字串位置

所以我们add函数实现里面,fmt拿到的就是rbp-0x14的地址,也就是第一个参数,随后的解析就是依据给的格式,把对应数据解析出来,移动指针ap的位置到合适地方(依据对齐原则,以及sizeof(数据类型)

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

C语言可变参数只会用算啥本事?看我来抽丝剥茧干翻它!相关推荐

  1. c语言怎样获得函数内参数的值_C语言可变参数函数的实现原理

    在本人的<C语言可变参数函数的实现方法>一文中,介绍了如何建立自己的可变参数函数. 下面继续介绍可变参数函数的实现原理. 在汇编语言程序设计中,详细介绍了子程序的实现思想: (1)子程序只 ...

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

    一.什么是可变参数函数 C语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function).这种函数需要固定数量的强制参数,后面是数量可变的可选参数. 其中,强制参数必须至少一 ...

  3. C语言可变参数函数(printf/scanf)

    C 语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function).这种函数需要固定数量的强制参数(mandatory argument),后面是数量可变的可选参数(opti ...

  4. c 语言 可变参数前要加形参,C/C++中可变参数的用法详细解析

    可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是int,double还可以是char*,类,结构体等等.可变参数是实现printf(),sprintf()等函数的关键之处, ...

  5. c语言 可变参数的宏,可变参数的宏__ VA_ARGS__的用法

    回顾 在[ANSIC几种特殊的标准定义]中我们讲述了比较常用的几项: __FILE__:正在编译文件的路径及文件名 __LINE__:正在编译文件的行号 __DATE__:编译时刻的日期字符串 如&q ...

  6. next用法C语言,C语言可变参数的使用

    先来个简单的例子:#include #include void test0(int num,...) { va_list ap; va_start(ap, num); while(num--) { p ...

  7. 参数控制c语言代码走向,C语言可变参数完全解读

    本文转自:http://www.cnblogs.com/wangyonghui/archive/2010/07/12/1776068.html 一.是什么 我们学习C语言时最经常使用printf()函 ...

  8. 关于C语言可变参数函数的一些研究和总结

    可变参数函数是指函数参数的个数.类型等是不固定的,需要在用户调用过程中,根据实际传入的参数来确定其类型.个数等信息.例如:可变参数函数printf可谓是在C开发过程中使用最多的标准输出库函数之一,因此 ...

  9. C语言可变参数函数的使用及相关函数介绍

    By qianghaohao(Xqiang) 在C语言中当一个函数参数无法列举出来,或者参数个数  不确定,这时我们将函数声明为可变参数的形式,根据需  要传适当个数的参数.举例如下: int fun ...

最新文章

  1. H5移动前端性能优化
  2. 如何实现模拟人类视觉注意力的循环神经网络?
  3. 网站如何集成百度UEditor编辑器
  4. python常用的绘图库_Python3绘图库Matplotlib(01)
  5. SpringCloud 多机搭建Consul集群
  6. shell 命令总结
  7. 上海应用技术大学计算机专业分数线,上海应用技术大学2016年上海市各专业录取分数线...
  8. View DrawingCache的理解
  9. 一款开源的微信小程序商城项目,接外包直接拿去改改,就能用。。。
  10. yolov3训练步骤
  11. ​手机APP应用软件开发
  12. LDA Effect Size分析 LEfSe详解
  13. oracle课堂收录-触发器
  14. 明源售楼系统技术解析(三)付款定义新增、修改、删除
  15. View的测量规则以及三大方法流程
  16. 日拱一卒,功不唐捐 | 每日思考俱乐部 专栏更新通知
  17. (补)单片机原理及应用学习笔记(三)
  18. 2022最新独立版智狐聚合支付v1.0.5.21_聚合支付系统源码
  19. 电路分析 笔记整理(模拟电子电路)
  20. iOS ZBarSDK 用ZBarReaderView自定义二维码扫描界面

热门文章

  1. Java 11快多少?
  2. Web应用程序安全性:战斗自己或寻找理智的边缘
  3. java 正则表达式使用_如何用正则表达式杀死Java
  4. Java 10中的本地类型推断,或者如果它像鸭子一样嘎嘎叫
  5. 同步器 java_您可能不知道的五个高级Java同步器
  6. 使用Java Servlet,JSP标签和Stormpath快速构建Java Web App
  7. osgi 模块化_OSGi案例研究:模块化vert.x
  8. JCG学院开设了Java设计模式课程!
  9. JPA教程:实体映射-第3部分
  10. JavaFX技巧7:使用CSS颜色常量/派生颜色