可变参数列表源码的剖析(可变参数调用可变参数)
本文目录一览:
- 1、关于C++可变参数的问题,请达人看下面代码,为什么24.0,如果没有后面的.0,会出现数据异常或者溢出呢?
- 2、c语言中什么是可变参数?最好有简单的应用可变参数的例子。谢谢
- 3、c++ 变长参数列表
- 4、C语言中可变参数宏的va_start(ap, v)
- 5、简单谈谈Python中函数的可变参数
关于C++可变参数的问题,请达人看下面代码,为什么24.0,如果没有后面的.0,会出现数据异常或者溢出呢?
我们按照32位系统来讲。
首先需要知道一些编译器的默认类型问题,整数常量默认为int(4字节),浮点数常量默认为double类型(8字节)。
其次,来看这一句:sum+=va_arg(ap,double);
你在这里指定了参数是double类型,va_arg的作用是从地址ap开始返回一个double类型的数,并且ap地址向后移动double类型所占的字节数,这一句分解下可以看成这样:
sum = sum + *(double *)ap;
ap = ap +8;
而如果参数里不加小数点的话,默认是int类型,在这里ap的地址加8的话直接就错位了,所以会混乱。
所以解决的办法就是,要么加小数点,要么显示指明数字常量位double类型,如:double iA=add(3,24.0,42.6,56.8);这句改成:
double iA=add(3,(double)24,(double)426,(double)568);
c语言中什么是可变参数?最好有简单的应用可变参数的例子。谢谢
一个简单的可变参数的函数的例子:
#include stdio.h
#include stdarg.h
void Func(int count, ...) //可变形参的函数的定义
{
va_list ap;
int n = count; //使用count来表示后面的参数个数
char *s = NULL;
int d = 0;
double f = 0.0;
va_start(ap, count); // 从第二个形参开始读取
s = va_arg(ap, char*); //为形参指定类型char*
d = va_arg(ap, int); //为形参指定类型int
f = va_arg(ap, double); //为形参指定类型double
va_end(ap); //读取形参结束
printf( "%s %d %f ", s, d, f); //这里可以做想要的功能了。
}
main()
{
Func(3, "Hello", 345, 788.234);
}
c++ 变长参数列表
在C编译器通常提供了一系列处理可变参数的宏,实现就像printf()那样的变长参数列表,这样可以屏蔽不同的硬件平台造成的差异,增加程序的可移植性。这些宏包括va_start、 va_arg和va_end等,这些宏都是在头文件stdarg.h里定义的。
采用ANSI标准形式时,参数个数可变的函数的原型声明是:
type funcname(type para1, type para2, ...)
这种形式至少需要一个普通的形式参数,后面的省略号不表示省略,而是函数原型的一部分。type是函数返回值和形式参数的类型。
不同的编译器,对这个可变长参数的实现不一样 ,gcc4.x中是采用内置函数的方法来实现。
接下来我们看看以下示例代码:
#include stdarg.h
#include stdio.h
int Sum (int n, ...)
{
int sum = 0, i = 0;
va_list p; // 定义一个变量 ,保存函数参数列表的指针。
va_start(p, n); // 用va_start宏初始化变量p,
// va_start宏的第2个参数n,
// 是一个固定的参数,
// 必须是我们自己定义的变长函数的最后一个入栈的参数,
// 也就是调用的时候参数列表里的第1个参数。
for (i = 1; i n; ++ i) // i从1开始,遍历所有可变参数。
{
sum += va_arg(p, int); // va_arg取出当前的参数,
// 并认为取出的参数是一个整数(int) 。
}
return sum;
}
int main(void)
{
int num;
num = Sum(5, 1, 2, 3, 4);
printf("%d\n", num);
return 0;
}
当我们调用Sum函数时,传递给Sum函数的参数列表的第一个参数n的值是5,va_start 初始化p使其指向第一个未命名的参数(n是有名字的参数) ,也就是1(第一个),每次对 va_arg的调用,都将返回一个参数,并且把 p 指向下一个参数,va_arg 用一个类型名来决定返回的参数是何种类型,以及在 var_arg的内部实现中决定移动多大的距离才到达下一个参数。
C语言中可变参数宏的va_start(ap, v)
我把你的提问分为3个问题:
1、为什么printf("%s", ap);输出不了?
2、va_start(ap, v)的定义中为什么使用二级指针?
3、va_arg(ap,t) 的定义中为什么用*(t *),它的作用是?
在解释之前,先确认一个小问题:
在C语言中,指针这种类型的大小实际上一样的,我的意思是说无论是char *a,还是int *a,或者是char **a,a这个指针变量所占用的内存空间是一样的(都是sizeof(a),究竟是等于4,还是8取决于CPU的位数)
先回答第一个问题:
你应该知道va_list的定义:typedef char * va_list;
也就是说ap可以理解为一个char *类型的变量,va_start(ap,c)这个执行之后,ap确实指向了可变参数列表中的第一个参数,注意【是ap这个指针指向了第一个参数】,而如果你的第一个参数是一个字符串(C语言中也就意味着是一个char*的变量),这样的话,ap这个指针就指向了一个char*类型的指针变量,【指向指针的指针变量是二级指针变量】这个我就不用多说了吧,所以printf("%s", ap);是无法输出的,而修改为printf("%s", *(char **)ap);应该就可以输出了!
然后是第二个问题:
这里先说一下函数调用过程中参数传递的问题:
【 函数参数是以数据结构:栈的形式存取,从右至左入栈。
首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:
void func(int x, char *y, char z);
那么,调用函数的时候,实参 char z 先进栈,然后是 char *y,最后是 int x,因此在内存中变量的存放次序是 x-y-z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。】
注意,x,y,z这几个变量是存放到堆栈中的,所以我们需要获得的不是y这个变量本身,而是它在堆栈中的地址,而ap这个指针变量就是保存着堆栈中函数入参的地址的,所以在va_start(ap, v)的定义中要使用v,而不管v变量本身是什么类型的(哪怕v是一个指针变量,甚至是二级指针)v都表示一个地址,所以可以强制转换为va_list类型(也就是char *)。
第三个问题:
要睡觉了,先自己想吧,如果还不明白,就留言追问吧。
简单谈谈Python中函数的可变参数
简单谈谈Python中函数的可变参数
在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。
可变参数( * )
可变参数,顾名思义,它的参数是可变的,比如列表、字典等。如果我们需要函数处理可变数量参数的时候,就可以使用可变参数。
我们在查看很多Python源码时,经常会看到 某函数(*参数1, **参数2)这样的函数定义,这个*参数和**参数就是可变参数,一时会让人有点费解。其实只要把函数可变参数的定义搞清楚了,就不难理解了。
当我们不知道需要用几个参数来定义函数的时候,可变参数就可以大展手脚了。
在Python里,带 * 的参数就是用来接受可变数量参数的。
如果一个函数定义如下:
def functionTest(*args):
....
....
....
调用时我们可以的这样调用:
functionTest(1)
或者
functionTest(1,2)
或者
functionTest(1,2,3)
后面可以传入多个参数。
看段实例代码,观察下*是怎么具体应用的吧:
def get_sum(*numbers):
sum = 0
for n in numbers:
sum += n
return sum
#在这里写下你的代码来调用get_sum来求5个数字的和,并输出这个结果
print (get_sum(1,2,3,4,5))
结果会是什么呢?大家可以自己动手操作起来看下,以就是关于Python中函数可变参数的全部内容,希望这篇文章对大家学习或使用python能有所帮助