可变参数的函数参考方案

可变参数的函数,写法如下:

type Function(固定参数1,固定参数2,……固定参数n,…);

可见,可变参数的函数有两种参数,一种是固定参数,一种是可变参数。

固定参数就是一定要输入的参数,其个数确定,类型确定。一般的函数都是使用固定参数。

可变参数用“…”来表示。其个数不固定。

一个可变参数的函数,至少要有1个固定参数。因为可变参数正是依靠最后一个固定参数来确定自身首地址。

可变参数函数使用va函数来对可变参数提供支持。

va函数定义在stdarg.h中,它们有:va_list,va_start(),va_arg(),va_copy(),va_end()。

①va_list:可变参数列表指针。调用va_start初始化后,该指针指向可变参数列表的第0号元素。依靠函数va_arg来调用列表元素并移动指针

②va_start(va_list对象,最后一个固定参数):va_list的初始化函数。其输入的两个参数分别为va_list对象和最后一个固定参数。使用最后一个固定参数来对va_list对象进行初始化。

比如

void Test(int n0,doublen1,char n2, ...)

{

va_listarg_ptr;

va_start(arg_ptr,n2);

……

}

其中最后一个固定参数是n2,所以va_start(arg_ptr,n2);的第二个参数是n2。这与最后一个固定参数的类型是无关的,固定参数可以是任何类型。

③va_arg(va_list对象, type):返回参数列表中指针所指的参数,返回类型为type,并使指针向下移动一个位置。即va_arg包含了两个功能:返回当前参数,并使指针指向下一个参数。

④va_copy(dest, src):dest,src的类型都是va_list,va_copy()用于复制参数列表指针,将dest初始化为src。

⑤va_end(va_list对象):清空参数列表,并将va_list对象设为无效。

va_start()/va_copy() … va_end()是成对的。关于va_list对象的一切操作都必须在这二者之间进行。

如果调用va_end()进行了清空,那么调用va_start()/va_copy()即可创建新的va_list对象。

注意,va_list对象是无法获取大小的,或者说无法获取va_list对象中有多少个参数。一般来说,获取va_list对象中的参数个数有两种方法:①通过函数传参传进来②在可变参数的最后再加一个参数,为0、-1或空字符串。这样可以在函数内部进行判断。

例:

1.通过传参形式:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
int sum( int count, ... )
{
         va_list arg_ptr;
         va_start( arg_ptr, count);
         int theSum= 0 ;
         for ( int i= 0 ;i<count;i++) pre= "" return = "" thesum= "" ><p> 2 .通过设最后一个不定参数为标志位:</p><pre class = "brush:java;" > int demo( char msg, ... )
{
          va_list arg_ptr;
          char para;
          va_start( arg_ptr, msg );
          while ( 1 )
          {
             para = va_arg( arg_ptr, char ); //输入的每个不定参数都是char类型
              if ( strcmp( para, "" ) == 0 )
             break ;
             调用para
          }
          va_end( arg_ptr);
          return 0 ;
}
</pre>
<p>调用方法:“demo( "DEMO" , "This" , "is" , "a" , "demo!" , "" );”,最后一个参数标示结束。</p>
<p>以上两种写法,都有个限制,那就是输入的所有不定参数都是同一类型的。因为va_arg(va_list对象, type)需要输入当前指向的参数类型,如果输入的多个不定参数类型不同,那么va_arg(va_list对象, type)的type参数就无法确定。</p>
<p>C使用的方法是由一个固定参数传入Char* pszFormat,该字符串中用%d/f/c等明确指明了传入参数的顺序和类型。这样,只要在函数内部解析这个固定参数,其中“%”的个数就是不定参数个数,不定参数类型依次解析%后的字符即可。</p>
<p>例:</p>
<pre class = "brush:java;" > void my_printf( const char * fmt, ... )
{
     va_list ap;
     va_start(ap,fmt); /* 用最后一个具有参数的类型的参数去初始化ap */
     for (;*fmt;++fmt)
     {
         /* 如果不是控制字符 */
         if (*fmt!= '%' )
         {
             continue ; //结束单次循环
         }
         /* 如果是控制字符,查看下一字符 */
         ++fmt;
         if ( '\0' ==*fmt) /* 如果是结束符 */
         {
             assert ( 0 );  /* 这是一个错误 */
             break ;
         }
         switch (*fmt)
         {
         case '%' : /* 连续2个'%'输出1个'%' */
             putchar( '%' );
             break ;
         case 'd' : /* 按照int输出 */
             {
                 /* 下一个参数是int,取出 */
                 int i = va_arg(ap, int );
                 printf( "%d" ,i);
             }
             break ;
         case 'c' : /* 按照字符输出 */
             {
                 /* 下一个参数是char,取出 */
                 //不可以用char c = va_arg(ap,char);
             int c = va_arg(ap, int );
                 printf( "%c" ,c);
             }
             break ;
         }
     }
     va_end(ap);  /* 释放ap */
}
</pre>
<p>关于 'c' 的解析,用的是 int c = va_arg(ap, int );</p>
<p>这是因为在C语言中,调用一个不带原型声明的函数时,调用者会对每个参数执行“默认实际参数提升( default argumentpromotions)”。</p>
<p>同时,对可变长参数列表超出最后一个有类型声明的形式参数之后的每一个实际参数,也将执行上述提升工作。</p>
<p>提升工作如下:</p>
<p>—— float 类型的实际参数将提升到 double </p>
<p>—— char short 和相应的signed、unsigned类型的实际参数提升到 int </p>
<p>——如果 int 不能存储原值,则提升到unsignedint</p>
<p>然后,调用者将提升后的参数传递给被调用者。</p>
<p>同理,如果需要使用 short float ,也应该这样:</p>
<pre class = "brush:java;" > short s = ( short )va_arg(ap, int );
float f = ( float )va_arg(ap, double );
</pre>
<p>总之,va_arg(ap,type)中的type绝对不能为以下类型:</p>
<p>—— char 、signedchar、unsignedchar</p>
<p>—— short 、unsignedshort</p>
<p>——signedshort、shortint、signedshortint、unsignedshortint</p>
<p>—— float </p>
</count;i++)>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Scala函数式编程》是一本非常实用的Scala编程书籍,旨在教读者如何使用Scala编程语言实现函数式编程。该书通过具体的实例和案例来阐述Scala函数式编程的核心概念和技术,包括函数式编程基础、函数的高阶抽象、类型系统、模式匹配、并发编程、I/O 和异常处理等方面内容。这些知识点包含了Scala编程语言的重要概念,可以帮助读者深入掌握Scala函数式编程的技术,并在实际应用中运用它们。此外,该书也涵盖了Scala代码风格和整洁性等方面,对编成良好的代码有很大的帮助。总之,这本书对于学习Scala函数式编程的人来说是非常有实践价值的一本书籍。 ### 回答2: Scala函数式编程的PDF是一本非常有价值的学习资料。对于想要深入学习Scala函数式编程的开发者,这本书提供了全面详尽的指导和实践经验,帮助开发者理解函数式编程的核心概念和思想,并将其应用于Scala程序开发中。 该书主要包括以下内容: 1.函数式编程的基本概念和原则,如不可变性、高阶函数、currying、尾递归等等。 2.函数式数据结构和算法的实现,包括列表、栈、队列、树、图等等。 3.如何使用Scala语言支持函数式编程的特性,如case class、模式匹配、参数化类型、协变和逆变等等。 4.如何使用Scala函数式编程框架,如Akka、Spark等来构建高效的分布式应用。 这本书主要适合已经有一定Scala编程基础或者其他函数式编程语言经验的开发者阅读,由于书中的内容较为深入和专业,对于初学者不太友好。但对于有一定基础的Scala开发者来说,该书是一本非常有价值的参考资料,可以帮助他们更深入地理解Scala函数式编程,提高代码质量和开发效率。 ### 回答3: Scala是一种支持函数式编程范式的编程语言,从而满足了编程语言发展中对于高度抽象和复杂数据处理的需求。Scala函数式编程pdf是一个学习Scala函数式编程理论和实践的重要资源。 Scala函数式编程pdf包含Scala函数式编程核心概念和技术,例如高阶函数、不可变性、模式匹配和递归等。它还涵盖了Scala函数式编程中的一些常见问题和解决方案,以及Scala函数式编程如何与面向对象编程 (OOP)相融合等。 Scala函数式编程pdf还提供了丰富的实际案例,包括使用Scala函数式编程技术实现算法、数据处理、Web应用程序、分布式编程等等。 总之,Scala函数式编程pdf是Scala程序员学习和实践函数式编程的重要资源,它提供了理论、实践和案例相结合的综合性学习体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值