可变参数列表源码的剖析(可变参数模板)
本文目录一览:
- 1、简单谈谈Python中函数的可变参数
- 2、关于C++可变参数的问题,请达人看下面代码,为什么24.0,如果没有后面的.0,会出现数据异常或者溢出呢?
- 3、c++ 变长参数列表
- 4、C语言可变参数传递的问题
- 5、c语言中什么是可变参数?最好有简单的应用可变参数的例子。谢谢
- 6、C语言中可变参数宏的va_start(ap, v)
简单谈谈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能有所帮助
关于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++ 变长参数列表
在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语言可变参数传递的问题
void fun1(int a, int b, const char *fmt, ...);
void fun2(const char *fmt, ...);.
可变参数列表源码的剖析你注意可变参数列表源码的剖析了可变参数列表源码的剖析,参数传递的可是const类型的,不可以改变哦~
传递出来的args当然也不会有变化。
(奇怪的是你的编译器没有报错吗?晕啊……)
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语言中可变参数宏的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 *)。
第三个问题:
要睡觉了,先自己想吧,如果还不明白,就留言追问吧。