鱼C论坛

 找回密码
 立即注册
查看: 2123|回复: 1

[技术交流] C语言的可变参数的宏定义是如何运行滴

[复制链接]
发表于 2017-2-16 22:20:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
                                                      开学了,就要考证了233333 可能就没有那么多时间了..

----------------------------------------写了个printf函数,于是就有了以下的感觉------------------------------------------

嗯!!可变参数是什么呢?
不直接告诉你~和大家举个例子..

不可变的参数:
void foo(int i,int n)

        ;


可变参数:
void foo1(int i,...)

        ;


接下来对以上两个函数进行调用,在编译的时候,给出了如下的警告:
warning C4020: “foo”: 实参太多.
什么foo函数的实参太多
是的实参太多了;那foo1输入了那么多个实参为什么不会出现实参太多的警告呢?
嗯.......是因为我们在foo1的函数中使用了可变参数啦!

从上面我们可以看出: 可变参数可以输入定义之外的参数而非可变参数则不行。

好啦,我们知道了什么是可变参数,那么可变参数这个功能到底放在什么地方呢?
接下下我们一起去扒一扒;

可变参数这个功能有一个专门的头文件来包含,这个头文件相信大家都很熟悉:<stdarg.h>
那么我们来介绍一下va系类的宏吧!
PS:va系列的宏,有点深度...--  (va :variable arguments  可变的参数

1. va_list   
typedef char* va_list;
哦哦哦,原来va_list只是char*的马甲,什么意思?说白了就是一个马甲,他的原型还是char*

2.va_start
这个是什么?懵逼!
额!我们在VS中用万能的F12看看吧..
#define va_start __crt_va_start 什么来的??再来个F12吧

#define __crt_va_start(ap, x) __crt_va_start_a(ap, x) 还是不懂;再来个F12吧

#define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))

额!ADDRESSOF(v)和_INTSIZEOF(v)是什么来的在F12吧

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

PS:此宏定义的作用是宏的开始!并指向下一个可变参数的参数

#define _ADDRESSOF(v) (&(v))

PS:此宏定义的作用是获取可变参数第一个参数的地址;
如果我们把这些都结合起来可以得到一下的结论:
接收第一个可变参数的地址,并指向下一个可变参数的地址
哈哈!原形毕露了把!

3.va_agr
#define va_arg   __crt_va_arg
#define __crt_va_arg(ap, t)     (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
谔谔!这个宏定义的主要分析是(*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))这个
那我们来一起分析一下吧!

第一个*是解引用;(t*)其实指的就是类型的转换;
关键点来了 ap += _INTSIZEOF(t),这里是把指针指向了下一个参数,
那 - _INTSIZEOF(t) 这个又是为什么呢?
上面我们的指针已经指向了下一个可变参数,这里又指向了一下个,
也就是说我们一共向后了2个参数,所以这里要放回一个虚值,而这个虚值正好就是上一个可变参数的地址
这个宏的作用是读取后面的可变参数

4.va_end
#define va_end   __crt_va_end
#define __crt_va_end(ap)        ((void)(ap = (va_list)0))
哦,这个嘛,一看就知道了,就是把清除指针

下面向大家分享我在写printf的疑问

为什么在打印%s的时候va_agr的参数为什么要写char *,为什么不能呢个用va_arg的方式来指向%s的数组呢?
因为啊,我们在输入字符串额时候,只是复制了字符串的地址,而并不是把整个字符串复制到可变参数中,
所以当我们指向了一个字符串的时候,其实是指向了可变参数的地址,所以我们要把,可变参数地址内的字符串地址给
取出来,所以我们把它转换了char**,然后在对他进行解引用,从而得到了字符串的地址。。。

--------------------------------------------------------写完了 请大家多多指教--------------------------------------------------





想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-2-18 20:00:30 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-27 22:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表